{"record":{"id":"a5685ccab712c3f0","repo":"garrytan/gstack","slug":"out-specified-more-than-once","errorCode":null,"errorMessage":"--out specified more than once","messagePattern":"--out specified more than once","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/read-commands.ts","lineNumber":72,"sourceCode":"}\n\n/**\n * Parse `--out <path>` / `--out=<path>` and `--raw` / `--raw=true|false` out of an\n * arg list, returning the flags plus the remaining positional args (`rest`).\n *\n * Single source of truth shared by the js/eval handlers and the write-capability\n * gate in server.ts, so the two never disagree on what counts as an `--out`\n * invocation. Throws on malformed usage (repeated `--out`, missing value, bad\n * `--raw` value) so the user gets a clear error instead of a silent misparse.\n */\nexport function parseOutArgs(args: string[]): OutArgs {\n  let outPath: string | undefined;\n  let raw = false;\n  const rest: string[] = [];\n  for (let i = 0; i < args.length; i++) {\n    const a = args[i];\n    if (a === '--out') {\n      if (outPath !== undefined) throw new Error('--out specified more than once');\n      const val = args[i + 1];\n      if (val === undefined || val.startsWith('--')) throw new Error('--out requires a file path');\n      outPath = val;\n      i++;\n    } else if (a.startsWith('--out=')) {\n      if (outPath !== undefined) throw new Error('--out specified more than once');\n      const val = a.slice('--out='.length);\n      if (val === '') throw new Error('--out requires a file path');\n      outPath = val;\n    } else if (a === '--raw') {\n      raw = true;\n    } else if (a.startsWith('--raw=')) {\n      const v = a.slice('--raw='.length).toLowerCase();\n      if (v !== 'true' && v !== 'false') throw new Error('--raw must be true or false');\n      raw = v === 'true';\n    } else {\n      rest.push(a);\n    }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/read-commands.ts#L54-L90","documentation":"Thrown by parseOutArgs when `--out <path>` (space-separated form) appears a second time in the same js/eval command. The parser tracks the first outPath and refuses a second to avoid a silent overwrite of the output target.","triggerScenarios":"Passing `browse js <expr> --out a.png --out b.png` — the second --out triggers the check because outPath is already set.","commonSituations":"Script or wrapper that appends --out automatically on top of a user-supplied --out; copy-paste duplication; shell alias that injects --out; arg array built by concatenation that double-adds the flag.","solutions":["Remove the duplicate --out — only one output path is allowed per command","Audit wrapper scripts and aliases that append --out automatically","Use --out=path form exactly once, explicitly","Build arg arrays with a Set or guard rather than naive push"],"exampleFix":"// before\nbrowse js 'document.title' --out a.json --out b.json  // throws\n\n// after\nbrowse js 'document.title' --out a.json","handlingStrategy":"validation","validationCode":"function hasSingleOutArg(args: string[]): boolean {\n  return args.filter(a => a === '--out' || a.startsWith('--out=')).length <= 1;\n}\n\nif (!hasSingleOutArg(args)) {\n  throw new Error('Only one --out flag is allowed per command');\n}","typeGuard":"function outArgCount(args: string[]): number {\n  return args.filter(a => a === '--out' || a.startsWith('--out=')).length;\n}","tryCatchPattern":"try {\n  parseOutArgs(args);\n} catch (e: any) {\n  if (/--out specified more than once/.test(e.message)) {\n    // keep only the first --out occurrence\n    const deduped: string[] = [];\n    let seen = false;\n    for (let i = 0; i < args.length; i++) {\n      if (args[i] === '--out' || args[i].startsWith('--out=')) {\n        if (seen) continue;\n        seen = true;\n        if (args[i] === '--out') { deduped.push(args[i], args[i + 1]); i++; }\n        else deduped.push(args[i]);\n      } else deduped.push(args[i]);\n    }\n    parseOutArgs(deduped);\n  } else throw e;\n}","preventionTips":["Dedupe the arg array before passing it to the command","Audit wrapper scripts and aliases that inject --out automatically","Use --out= exactly once, explicitly","Build arg arrays with a guard: only push --out if outPath is not already set"],"tags":["cli","args","usage-error","out-flag","duplicate"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}