{"record":{"id":"199784254d8aa4ec","repo":"windmill-labs/windmill","slug":"scriptpath-declares-no-s3object-parameter-to-bi","errorCode":null,"errorMessage":"${scriptPath} declares no S3Object parameter to bind --upload to.","messagePattern":"(.+?) declares no S3Object parameter to bind --upload to\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/pipeline/pipeline.ts","lineNumber":496,"sourceCode":"      const ls = localScripts?.get(scriptPath);\n      if (!ls) {\n        throw new Error(`No local file for ${scriptPath} to infer its S3Object parameter.`);\n      }\n      schema = (await inferSchema(ls.language as any, ls.content, {}, scriptPath)).schema;\n    } else {\n      schema = (await wmill.getScriptByPath({ workspace: workspaceId, path: scriptPath })).schema;\n    }\n    return schema;\n  };\n\n  const args: Record<string, any> = {};\n  for (const binding of bindings) {\n    let param = binding.param;\n    if (!param) {\n      const params = s3ObjectParams(await loadSchema());\n      if (params.length === 1) param = params[0];\n      else if (params.length === 0) {\n        throw new Error(`${scriptPath} declares no S3Object parameter to bind --upload to.`);\n      } else {\n        throw new Error(\n          `${scriptPath} has multiple S3Object parameters (${params.join(\", \")}) — pick one with --upload ${binding.scriptTok}:<param>=${binding.source}`,\n        );\n      }\n    }\n    if (param in args) {\n      throw new Error(`--upload binds ${scriptPath}:${param} more than once.`);\n    }\n    let obj: { s3: string; storage?: string };\n    if (binding.source.startsWith(\"s3://\")) {\n      // Canonical `s3://<storage>/<key>`; keeps named storage (see parseS3Uri).\n      obj = parseS3Uri(binding.source);\n    } else {\n      const buf = await readFile(binding.source);\n      // Key scoped by script + param so distinct sources sharing a basename\n      // (across scripts or params) don't clobber each other in the store.\n      const key = devUploadKey(scriptPath, param, binding.source);","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/pipeline/pipeline.ts#L478-L514","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add or restore an S3Object-typed parameter in the target script's signature and re-push it.","Explicitly name the parameter with `--upload <tok>:<param>=<source>` if a compatible param exists but wasn't auto-detected.","If the param was just added, re-pull/ensure the server has the updated schema before running.","Point --upload at the correct script token if the S3Object param lives on a different step."],"exampleFix":"// before (script signature)\nexport async function main(path: string) {...}\n\n// after\nimport { S3Object } from \"windmill-sdk\";\nexport async function main(file: S3Object, path: string) {...}","handlingStrategy":"validation","validationCode":"const schema = await getScriptSchema(scriptPath);\nconst s3Params = Object.entries(schema?.properties ?? {})\n  .filter(([, p]: any[]) => p?.type === \"S3Object\" || p?.format === \"s3object\")\n  .map(([k]) => k);\nif (s3Params.length === 0) throw new Error(`${scriptPath} has no S3Object param; use --upload <tok>:<param>=... or fix the script`);","typeGuard":null,"tryCatchPattern":"try {\n  await run({ upload: [\"f=source\"], /* ... */ });\n} catch (e: any) {\n  if (e.message.includes(\"declares no S3Object parameter\")) {\n    console.error(`${e.message} — add an S3Object param to the script or bind explicitly with --upload <tok>:<param>=...`);\n  }\n  throw e;\n}","preventionTips":["Type file-consuming script params as S3Object (windmill-sdk) so auto-binding can find them.","Re-push scripts after signature changes so the server schema matches what --upload expects.","Bind explicitly with `--upload <tok>:<param>=<source>` whenever more than one script/param could match.","Check the inferred schema (`wmill script show <path>`) before wiring --upload."],"tags":["cli","validation","parameters"],"backgroundTag":"missing-s3object-parameter","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}