windmill-labs/windmill · warning

--upload for ${p} is unused — it isn't in the run selection.

Error message

--upload for ${p} is unused — it isn't in the run selection.

What it means

In `wmill pipeline run`, each --upload binding whose target script did not make it into the final run selection is a silent no-op, so the CLI warns per path. It tells you the binding value will never be consumed by this run.

Source

Thrown at cli/src/commands/pipeline/pipeline.ts:911

    return defaultPartitionValue(kind);
  };
  if (opts.local && !opts.partition) {
    const unresolvable = order.filter(
      (p) => partitionKindByPath.get(p) === "dynamic",
    );
    if (unresolvable.length > 0) {
      throw new Error(
        `dynamic \`// partitioned\` script(s) need an explicit partition for a local run: ${unresolvable.sort().join(", ")} — pass --partition <value>.`,
      );
    }
  }

  // A `--upload` whose script fell outside the selection is a no-op the user
  // should know about, rather than silently ignored.
  const orderSet = new Set(order);
  const boundInOrder = [...boundBindingsByPath.keys()].filter((p) => orderSet.has(p)).sort();
  for (const p of boundBindingsByPath.keys()) {
    if (!orderSet.has(p)) log.warn(`--upload for ${p} is unused — it isn't in the run selection.`);
  }
  for (const p of plainArgsByPath.keys()) {
    if (!orderSet.has(p)) log.warn(`--arg for ${p} is unused — it isn't in the run selection.`);
  }

  if (opts.json) {
    // Surface reachable/dropped ends so a machine-readable plan reflects the
    // same trimming the human-facing warning does — a resolved-but-unreachable
    // `--to` must not look like a clean plan that silently runs only the start.
    console.log(
      JSON.stringify({
        start: runAll ? null : scriptPathOf(start!),
        ends: ends.map(idLabel),
        reachableEnds: reachableEnds.map(idLabel),
        droppedEnds: droppedEnds.map(idLabel),
        order,
        cyclic,
        uploads: boundInOrder,

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check the plan output (use --json to see reachable/dropped ends) and widen the selection (--start/--end) so the script runs.
  2. Correct the path in --upload if it is misspelled or renamed.
  3. Remove the unused --upload flag if the binding is no longer needed.
  4. Resolve cycles/barriers that excluded the script (see other warnings in the same run).

Example fix

// before: bound script not in selection
wmill pipeline run f/myflow --start a --end b --upload f/myflow/c=file.csv
// after: widen window to include c
wmill pipeline run f/myflow --start a --end c --upload f/myflow/c=file.csv
Defensive patterns

Strategy: validation

Validate before calling

// confirm every --upload target is inside the planned selection
const plan = JSON.parse(execSync('wmill pipeline run f/x --start a --end b --json').toString());
const uploads = ['f/myflow/c'];
const missing = uploads.filter(p => !plan.order.includes(p));
if (missing.length) throw new Error(`--upload targets not in selection: ${missing}`);

Prevention

When it happens

Trigger: Passing --upload <path>=<value> for a script that was excluded from the selection — outside the --start/--end window, behind a barrier, on a cycle, filtered as not-runnable, or the path has a typo.

Common situations: Leftover --upload flags from a previous run invocation; uploading to a script that is not downstream of --start; a --to/--end narrowing that quietly excluded the bound script.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/18d98397beccb56d. Report an issue: GitHub.