skip to content

What is `gradle.startParameter.taskNames`, when is it a legitimate thing to read, and what are its limits?

level: seniorimportance: should knowfreq 25%

answer

  1. requested selectors, not resolved graph
  2. available early (init/config)
  3. misses transitive/default/plugin tasks
  4. fine for telemetry, wrong for 'will X run'
  5. excludedTaskNames for -x

basics

~20 s

startParameter.taskNames is the list of raw task-name strings (and selectors) the user requested on the command line. It reflects intent, not the resolved graph, so it's fine for telemetry/diagnostics but wrong for 'will task X run?' decisions.

solid answer

~40 s

`gradle.startParameter` captures the invocation's parameters; `taskNames` is the `List<String>` of requested task selectors exactly as parsed (before transitive resolution and after abbreviation expansion is applied at run time, the stored strings are the requested selectors). It's available very early — during initialization/configuration — which is its main advantage over the task graph. Legitimate uses: logging what was requested, build-scan tagging, or coarse early decisions (e.g. tweaking settings before the graph exists). Illegitimate uses: deciding whether a task will execute — that needs the *resolved* graph via `taskGraph.hasTask`. `taskNames` won't contain transitively-scheduled tasks, default tasks, or plugin-injected ones, and may be empty (default tasks). Treat it as 'what the user asked for', never 'what will run'.

code

kotlin · 7 lines
kotlin
// Legit early use: tag the build by requested intent
val requested = gradle.startParameter.taskNames
val excluded = gradle.startParameter.excludedTaskNames
logger.lifecycle("Requested=\$requested excluded=\$excluded")

// WRONG for execution decisions — use taskGraph.hasTask instead:
// if (requested.contains("test")) { ... }   // misses build -> test

go deeper

for a junior

Know it's the list of tasks the user typed on the command line.

for a middle

Distinguish requested intent from the resolved graph; don't use it to decide whether a task will run.

for a senior

Explain its key advantage (early availability before the graph) and its precise limits (transitive/default/plugin tasks, selectors vs paths).

for a principal

Set guidance for init scripts/conventions plugins on when intent-based early reads are acceptable versus mandating graph-based decisions for correctness.

## StartParameter: the invocation snapshot `gradle.startParameter` is a `StartParameter` object describing *how the build was invoked*: requested task names, project dir, log level, `--offline`, `--continue`, system/project properties, excluded tasks, and more. The relevant piece here is: - `taskNames: List<String>` — the requested task selectors as parsed from the command line (and any `defaultTasks` substitution when nothing was typed). - `excludedTaskNames: Set<String>` — tasks excluded with `-x`/`--exclude-task`. ### Requested intent, available early The defining property is **availability**: `startParameter` exists from the very start of the build (initialization, settings evaluation, configuration), long before the task graph is populated. So if you must make a decision *before* the graph exists — for instance in `settings.gradle.kts`, or to conditionally apply a plugin at configuration time — `taskNames` is sometimes the only signal you have. ### Why it's not the executed set `taskNames` is the *requested* intent and nothing more: - It excludes **transitively-scheduled** tasks (`build` requested → `test` scheduled but not in the list). - For **default tasks**, the user typed nothing; the list contains the configured defaults, not a guarantee of the final graph. - It does not account for tasks added by **plugins** via `dependsOn`/`finalizedBy` after the fact. - It carries **selectors**, which may be project-relative or abbreviated, not normalized absolute paths. Thus any logic of the form 'if task X will run, do Y' must use `gradle.taskGraph.hasTask(":path:X")` after `whenReady`, not `taskNames.contains("X")`. ### Legitimate patterns ```kotlin // settings.gradle.kts — coarse, early, intent-based decision val requested = startParameter.taskNames if (requested.any { it.endsWith("publish") }) { logger.lifecycle("Release-style invocation requested") } ``` Good uses: diagnostics/telemetry, build-scan tags, deciding *very early* settings-time behavior where no graph exists, and reading `--exclude-task` intent. Even then, prefer the graph once it's available. ### Mutability caveat `StartParameter` is partly mutable (e.g. you can programmatically set task names in an init script), but mutating it to drive logic is brittle and discouraged. Read it as a snapshot of intent; let the graph be the source of truth for execution decisions. ### Mental model - `startParameter.taskNames` = *what the user asked for* (early, intent). - `taskGraph.allTasks` / `hasTask` = *what Gradle will run* (post-config, truth).

  • Give one legitimate reason to read startParameter.taskNames over the task graph.
    Availability: startParameter exists during initialization/settings evaluation, before the task graph is populated. For very early, intent-based decisions it may be the only signal.
  • How do you see tasks the user excluded with -x?
    gradle.startParameter.excludedTaskNames gives the set of task names excluded via -x/--exclude-task.
  • Why is taskNames.contains("test") an unreliable gate?
    It only reflects requested intent. test is commonly scheduled transitively by build/check and won't appear in the requested list, giving a false negative.

saying these in an interview costs you the question

  • Treating startParameter.taskNames as the set of tasks that will execute.
  • Mutating StartParameter to drive build behavior as a normal pattern.
  • Ignoring that the list can be empty when defaultTasks apply.

context