windmill-labs/windmill · error · Error

--upload '${spec}' must be <script>[:<param>]=<file-or-s3-ur

Error message

--upload '${spec}' must be <script>[:<param>]=<file-or-s3-uri>

What it means

Syntax validation in parseUploadBinding: the --upload spec doesn't match <script>[:<param>]=<file-or-s3-uri>. The parser splits on the first '=' and expects a non-empty script token on the left and a source on the right; the throw fires when either side is missing — e.g. no '=' at all, empty script name, or empty source. The input at fault is the --upload string as typed.

Source

Thrown at cli/src/commands/pipeline/pipelineUpload.ts:21

// `data_upload` / `webhook` entry point so it (and its downstream) runs in the
// cascade instead of being skipped for want of input;
// `--arg <script>:<param>=<value>` passes a plain (non-S3Object) run arg.
import { basename } from "node:path";

export type UploadBinding = { scriptTok: string; param?: string; source: string };

/**
 * Parse a `--upload` spec: `<script>[:<param>]=<file-or-s3-uri>`.
 * Split on the FIRST `=` so an `s3://…` source (whose `:` sits to the right of
 * it) stays unambiguous; an optional `:<param>` on the left names the target
 * S3Object argument when the script declares more than one.
 */
export function parseUploadBinding(spec: string): UploadBinding {
  const eq = spec.indexOf("=");
  const left = eq < 0 ? "" : spec.slice(0, eq).trim();
  const source = eq < 0 ? "" : spec.slice(eq + 1).trim();
  if (!left || !source) {
    throw new Error(`--upload '${spec}' must be <script>[:<param>]=<file-or-s3-uri>`);
  }
  const colon = left.indexOf(":");
  if (colon < 0) return { scriptTok: left, source };
  const scriptTok = left.slice(0, colon).trim();
  const param = left.slice(colon + 1).trim();
  if (!scriptTok || !param) {
    throw new Error(`--upload '${spec}' must be <script>[:<param>]=<file-or-s3-uri>`);
  }
  return { scriptTok, param, source };
}

export type ArgBinding = { scriptTok: string; param: string; value: unknown };

/**
 * Parse an `--arg` spec: `<script>:<param>=<value>`. Split on the FIRST `=`
 * (values may contain `=`); the value is JSON when it parses as JSON, else the
 * raw string — so `stats:limit=10` is a number and
 * `daily_report:partition=2026-07-02` a string. `:<param>` is required: unlike

View on GitHub (pinned to e474e8803c)

Solutions

  1. Use the documented shape: --upload myscript=./data.csv or --upload myscript:input_file=s3://bucket/key
  2. Check for shell-quoting issues that stripped the '=' or the value
  3. Ensure neither side of the first '=' is empty
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at cli/src/commands/pipeline/pipelineUpload.ts:21 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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