{"record":{"id":"8bf0368910e48f03","repo":"windmill-labs/windmill","slug":"flag-tok-matches-multiple-scripts-match","errorCode":null,"errorMessage":"${flag} '${tok}' matches multiple scripts (${matches.map((r) => r.path).sort().join(\", \")}) — use the full path.","messagePattern":"(.+?) '(.+?)' matches multiple scripts \\((.+?)\\) — use the full path\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/pipeline/pipeline.ts","lineNumber":638,"sourceCode":"        `/w/${workspace.workspaceId}/assets/graph?folder=${encodeURIComponent(f)}&asset_kinds=${ASSET_KINDS}`,\n      ),\n    );\n    // Recover marker-only `data_upload`/`webhook`/`email` triggers the graph\n    // endpoint can't emit, so input-only entrypoints are cut here as they are\n    // under `--local` (else they'd auto-run empty).\n    await enrichDeployedNonAutorunTriggers(workspace.workspaceId, graph);\n  }\n\n  // Resolve a `--upload`/`--arg` script token to its graph node, with an\n  // actionable error when the short name is ambiguous or matches nothing.\n  const resolveScriptTokenOrThrow = (tok: string, flag: string): string => {\n    const id = resolveToken(graph, tok);\n    if (!id || !id.startsWith(\"script:\")) {\n      const matches = graph.runnables.filter(\n        (r) => r.usage_kind === \"script\" && (r.path.split(\"/\").pop() ?? r.path) === tok,\n      );\n      if (matches.length > 1) {\n        throw new Error(\n          `${flag} '${tok}' matches multiple scripts (${matches.map((r) => r.path).sort().join(\", \")}) — use the full path.`,\n        );\n      }\n      throw new Error(`${flag} '${tok}' matched no script in f/${f}.`);\n    }\n    return id;\n  };\n\n  // `--upload <script>[:<param>]=<file|s3://key>` binds an object to a\n  // data_upload/webhook entry point so it becomes a runnable start (and its\n  // downstream is no longer cut) — the arg is injected at execution. Repeatable\n  // per script (accumulated) so a multi-S3Object entry can bind each param.\n  const boundBindingsByPath = new Map<string, UploadBinding[]>();\n  const boundNodeIds = new Set<string>();\n  for (const spec of opts.upload ?? []) {\n    const binding = parseUploadBinding(spec);\n    const id = resolveScriptTokenOrThrow(binding.scriptTok, \"--upload\");\n    const p = scriptPathOf(id);","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/pipeline/pipeline.ts#L620-L656","documentation":"Ambiguity guard in resolveScriptTokenOrThrow: the short name given to --upload or --arg resolves to multiple script nodes in the workspace graph (same basename under different folders), and the CLI needs exactly one to bind the argument to. The message lists every matching full path sorted, and the fix is to use a full path. The input at fault is the abbreviated script token.","triggerScenarios":"Thrown at cli/src/commands/pipeline/pipeline.ts:638 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Re-run using the full script path from the listed candidates, e.g. --arg folder/sub/script:param=value","Rename one of the colliding scripts so short names are unique"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}