{"record":{"id":"7f5e97dc55a8611e","repo":"JuliusBrussee/caveman","slug":"arg-requires-a-value","errorCode":null,"errorMessage":"${arg} requires a value","messagePattern":"(.+?) requires a value","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/stats-cli.ts","lineNumber":42,"sourceCode":"export type StatsCLIOptions = {\n  json: boolean;\n  plain: boolean;\n  open: boolean;\n  out?: string;\n  filters: string[];\n};\n\nexport function parseStatsOptions(argv: string[]): StatsCLIOptions {\n  const result: StatsCLIOptions = { json: false, plain: false, open: false, filters: [] };\n  const seen = new Set<string>();\n  const valueFlags = new Set([\"--days\", \"--provider\", \"--model\", \"--agent\", \"--auth\", \"--out\"]);\n  for (let i = 0; i < argv.length; i++) {\n    const arg = argv[i]!;\n    if (seen.has(arg)) throw new Error(`duplicate ${arg}`);\n    seen.add(arg);\n    if (valueFlags.has(arg)) {\n      const value = argv[++i];\n      if (!value || value.startsWith(\"--\") || /[\\u0000-\\u001f\\u007f]/u.test(value)) throw new Error(`${arg} requires a value`);\n      if (arg === \"--days\" && (!/^\\d+$/u.test(value) || Number(value) < 1 || Number(value) > 3660)) {\n        throw new Error(\"--days must be an integer from 1 to 3660\");\n      }\n      if (arg === \"--out\") result.out = value;\n      else result.filters.push(arg, value);\n    } else if (arg === \"--json\") result.json = true;\n    else if (arg === \"--plain\" || arg === \"--no-open\") result.plain = true;\n    else if (arg === \"--open\") result.open = true;\n    else if (arg === \"--all-time\") result.filters.push(\"--days\", \"0\");\n    else throw new Error(`unknown option ${arg}`);\n  }\n  if (seen.has(\"--days\") && seen.has(\"--all-time\")) throw new Error(\"choose --days or --all-time\");\n  if (result.plain && result.open) throw new Error(\"choose --plain or --open\");\n  if (result.json && result.open) throw new Error(\"--json cannot open a browser\");\n  return result;\n}\n\ntype StatsMetrics = {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/stats-cli.ts#L24-L60","documentation":"Value-taking flags (--days, --provider, --model, --agent, --auth, --out) require exactly one following value. The parser throws if the next token is missing, is another flag (starts with '--'), or contains control characters — it never silently consumes the next flag as a value.","triggerScenarios":"`stats --days` with nothing after it; `stats --provider --json` (next token looks like a flag); a value containing control characters (e.g. from a broken terminal paste or unescaped newline in a script).","commonSituations":"Truncated command from a shell history paste; forgot the value because it was optional elsewhere; an env var interpolating to empty so the flag becomes last token; values with embedded newlines from YAML/JSON expansion.","solutions":["Supply a value immediately after the flag: `--days 30`, `--provider openai`","Quote values that could be empty or contain odd characters: `--model \"gpt-4o\"`","If the value comes from a variable, check it is non-empty before invoking the CLI"],"exampleFix":"// before\nmyapp stats --provider\n// after\nmyapp stats --provider openai","handlingStrategy":"validation","validationCode":"function requireValue(argv, flag) {\n  const i = argv.indexOf(flag);\n  const v = i !== -1 ? argv[i + 1] : undefined;\n  if (!v || v.startsWith(\"--\") || /[\\u0000-\\u001f\\u007f]/u.test(v)) {\n    throw new Error(`${flag} requires a value`);\n  }\n  return v;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const opts = parseStatsOptions(argv);\n} catch (e) {\n  if (String(e.message).endsWith(\"requires a value\")) {\n    console.error(e.message); process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always place the value immediately after the flag, space-separated","Quote values; guard interpolated env vars for emptiness before invocation","Strip trailing flags from scripts so a value-flag is never the last token"],"tags":["cli","argument-parsing"],"backgroundTag":"missing-cli-argument","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}