{"record":{"id":"0ea3f3826f32fe5d","repo":"ruvnet/ruflo","slug":"invalid-worker-spec-spec-expected-platfo","errorCode":null,"errorMessage":"Invalid --worker spec \"${spec}\". Expected \"<platform>:<role>:<prompt>\" (platform = claude|codex).","messagePattern":"Invalid --worker spec \"(.+?)\"\\. Expected \"<platform>:<role>:<prompt>\" \\(platform = claude\\|codex\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/dual-mode/cli.ts","lineNumber":271,"sourceCode":"        console.log();\n      });\n    });\n}\n\n/**\n * Parse `--worker \"<platform>:<role>:<prompt>\"` specs into WorkerConfig[].\n * Splits on the first two `:` so the prompt may itself contain colons.\n * Workers chain sequentially (each depends on the previous) unless `parallel`.\n */\nexport function parseWorkerSpecs(specs: string[], parallel: boolean): WorkerConfig[] {\n  const usedIds = new Set<string>();\n  const workers: WorkerConfig[] = [];\n\n  specs.forEach((spec, index) => {\n    const firstColon = spec.indexOf(':');\n    const secondColon = firstColon >= 0 ? spec.indexOf(':', firstColon + 1) : -1;\n    if (firstColon < 0 || secondColon < 0) {\n      throw new Error(`Invalid --worker spec \"${spec}\". Expected \"<platform>:<role>:<prompt>\" (platform = claude|codex).`);\n    }\n    const platformRaw = spec.slice(0, firstColon).trim().toLowerCase();\n    const role = spec.slice(firstColon + 1, secondColon).trim() || `worker-${index + 1}`;\n    const prompt = spec.slice(secondColon + 1).trim();\n    if (!prompt) {\n      throw new Error(`Invalid --worker spec \"${spec}\". Missing prompt after \"<platform>:<role>:\".`);\n    }\n    if (platformRaw !== 'claude' && platformRaw !== 'codex') {\n      throw new Error(`Invalid platform \"${platformRaw}\" in --worker spec \"${spec}\". Use \"claude\" or \"codex\".`);\n    }\n    const platform: 'claude' | 'codex' = platformRaw;\n\n    // Derive a unique id from the role.\n    const base = role.replace(/\\s+/g, '-');\n    let id = base;\n    let suffix = 2;\n    while (usedIds.has(id)) { id = `${base}-${suffix++}`; }\n    usedIds.add(id);","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/dual-mode/cli.ts#L253-L289","documentation":"parseWorkerSpecs() parses each --worker CLI argument with the format <platform>:<role>:<prompt>, splitting on the first two colons so the prompt itself may contain colons. This variant is thrown when fewer than two colons exist in the spec — i.e. the role or prompt segment is structurally missing, so the string can never satisfy the three-part format no matter what its contents are.","triggerScenarios":"(1) `--worker \"claude:implement\"` — platform and role only, no prompt; (2) `--worker \"claude\"` — platform only; (3) using a different separator such as `--worker \"claude|impl|do it\"`; (4) shell quoting that eats part of the argument.","commonSituations":"Composing ad-hoc dual-mode commands from memory and dropping the third segment; copying examples that used a template name instead of a full spec; unquoted specs where the shell splits tokens at spaces and the parser receives a fragment.","solutions":["Supply all three segments: `--worker \"claude:implementer:Add JWT auth to the login endpoint\"`.","Remember only the first two colons are structural — the prompt after the second colon may itself contain colons freely.","Quote the entire spec in the shell so it arrives as a single argv entry.","If you only have a platform and role in mind, you still must provide a non-empty prompt describing the task."],"exampleFix":"# before\n$ dual-mode collaborate --worker \"claude:reviewer\"\nError: Invalid --worker spec \"claude:reviewer\". Expected \"<platform>:<role>:<prompt>\" ...\n\n# after\n$ dual-mode collaborate --worker \"claude:reviewer:Review src/auth for timing-safe comparisons\"","handlingStrategy":"validation","validationCode":"function isValidWorkerSpec(spec: string): boolean {\n  const first = spec.indexOf(':');\n  const second = first >= 0 ? spec.indexOf(':', first + 1) : -1;\n  return first >= 0 && second >= 0 && spec.slice(second + 1).trim().length > 0 &&\n    ['claude', 'codex'].includes(spec.slice(0, first).trim().toLowerCase());\n}\nconst specs = rawSpecs.filter(Boolean);\nif (!specs.every(isValidWorkerSpec)) {\n  throw new Error(`bad --worker spec; expected \"<platform>:<role>:<prompt>\"`);\n}\nconst workers = parseWorkerSpecs(specs, parallel);","typeGuard":null,"tryCatchPattern":"try {\n  const workers = parseWorkerSpecs(specs, parallel);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid --worker spec')) {\n    console.error('Usage: --worker \"<claude|codex>:<role>:<prompt>\" (prompt may contain colons; quote the whole spec)');\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Quote each --worker argument so the shell delivers it as one argv entry","Only the first two colons are structural — write prompts naturally, colons included","Template specs in a shared script instead of typing them interactively","Run parseWorkerSpecs over your spec list in a dry-run mode before launching real workers"],"tags":["dual-mode","cli-arguments","parsing","worker-spec"],"backgroundTag":"invalid-cli-argument-format","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}