windmill-labs/windmill · error · Error

${scriptPath} declares no S3Object parameter to bind --uploa

Error message

${scriptPath} declares no S3Object parameter to bind --upload to.

What it means

Thrown by resolveUploadArgs when `--upload <token>=<source>` is given without naming a parameter, and the referenced script declares zero S3Object parameters for the CLI to bind to. The CLI tries to auto-select when exactly one S3Object param exists, but with none it cannot attach the uploaded file and aborts with this message.

Source

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

      const ls = localScripts?.get(scriptPath);
      if (!ls) {
        throw new Error(`No local file for ${scriptPath} to infer its S3Object parameter.`);
      }
      schema = (await inferSchema(ls.language as any, ls.content, {}, scriptPath)).schema;
    } else {
      schema = (await wmill.getScriptByPath({ workspace: workspaceId, path: scriptPath })).schema;
    }
    return schema;
  };

  const args: Record<string, any> = {};
  for (const binding of bindings) {
    let param = binding.param;
    if (!param) {
      const params = s3ObjectParams(await loadSchema());
      if (params.length === 1) param = params[0];
      else if (params.length === 0) {
        throw new Error(`${scriptPath} declares no S3Object parameter to bind --upload to.`);
      } else {
        throw new Error(
          `${scriptPath} has multiple S3Object parameters (${params.join(", ")}) — pick one with --upload ${binding.scriptTok}:<param>=${binding.source}`,
        );
      }
    }
    if (param in args) {
      throw new Error(`--upload binds ${scriptPath}:${param} more than once.`);
    }
    let obj: { s3: string; storage?: string };
    if (binding.source.startsWith("s3://")) {
      // Canonical `s3://<storage>/<key>`; keeps named storage (see parseS3Uri).
      obj = parseS3Uri(binding.source);
    } else {
      const buf = await readFile(binding.source);
      // Key scoped by script + param so distinct sources sharing a basename
      // (across scripts or params) don't clobber each other in the store.
      const key = devUploadKey(scriptPath, param, binding.source);

View on GitHub (pinned to e474e8803c)

Solutions

  1. Add or restore an S3Object-typed parameter in the target script's signature and re-push it.
  2. Explicitly name the parameter with `--upload <tok>:<param>=<source>` if a compatible param exists but wasn't auto-detected.
  3. If the param was just added, re-pull/ensure the server has the updated schema before running.
  4. Point --upload at the correct script token if the S3Object param lives on a different step.

Example fix

// before (script signature)
export async function main(path: string) {...}

// after
import { S3Object } from "windmill-sdk";
export async function main(file: S3Object, path: string) {...}
Defensive patterns

Strategy: validation

Validate before calling

const schema = await getScriptSchema(scriptPath);
const s3Params = Object.entries(schema?.properties ?? {})
  .filter(([, p]: any[]) => p?.type === "S3Object" || p?.format === "s3object")
  .map(([k]) => k);
if (s3Params.length === 0) throw new Error(`${scriptPath} has no S3Object param; use --upload <tok>:<param>=... or fix the script`);

Try / catch

try {
  await run({ upload: ["f=source"], /* ... */ });
} catch (e: any) {
  if (e.message.includes("declares no S3Object parameter")) {
    console.error(`${e.message} — add an S3Object param to the script or bind explicitly with --upload <tok>:<param>=...`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `wmill pipeline run --upload <scriptTok>:<source>` against a script whose JSON schema (inferred locally or fetched from the server) contains no parameter of type S3Object — e.g. the parameter is a plain string/path, the schema is empty, or the uploaded source targets the wrong script token.

Common situations: Script signature changed from S3Object to string and the run command wasn't updated; the --upload token points at the wrong entrypoint in the pipeline; schema not yet pushed to the server after adding the S3Object param; a hand-written script missing the s3_object import/typing.

Related errors


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