{"record":{"id":"e0c1ba322e342e9b","repo":"nanocoai/nanoclaw","slug":"flag-must-be-a-number-got-v","errorCode":null,"errorMessage":"${flag} must be a number, got \"${v}\"","messagePattern":"(.+?) must be a number, got \"(.+?)\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/crud.ts","lineNumber":424,"sourceCode":"  }\n\n  const out: Record<string, unknown> = { ...args };\n  for (const def of defs) {\n    const flag = `--${def.name.replace(/_/g, '-')}`;\n    const v = args[def.name];\n    if (v === undefined) {\n      if (def.required) throw new Error(`${flag} is required`);\n      if (def.default !== undefined) out[def.name] = def.default;\n      continue;\n    }\n    // The client parses a value-less `--flag` as boolean true.\n    if (v === true && def.type !== 'boolean') {\n      throw new Error(`${flag} requires a value`);\n    }\n    switch (def.type) {\n      case 'number': {\n        const n = Number(v);\n        if (Number.isNaN(n)) throw new Error(`${flag} must be a number, got \"${v}\"`);\n        out[def.name] = n;\n        break;\n      }\n      case 'boolean': {\n        if (v === true || v === 'true' || v === '1') out[def.name] = true;\n        else if (v === false || v === 'false' || v === '0') out[def.name] = false;\n        else throw new Error(`${flag} must be true or false, got \"${v}\"`);\n        break;\n      }\n      case 'json': {\n        if (typeof v === 'string') {\n          try {\n            out[def.name] = JSON.parse(v);\n          } catch (err) {\n            throw new Error(`${flag} must be valid JSON`, { cause: err });\n          }\n        }\n        break;","sourceCodeStart":406,"sourceCodeEnd":442,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/cli/crud.ts#L406-L442","documentation":"A flag declared with `type: 'number'` received a value that `Number()` coerces to NaN. Validation throws before the handler runs, echoing the offending value.","triggerScenarios":"Passing non-numeric text to a number flag: `--priority high`, `--count 10px`; passing an empty string; passing a boolean-adjacent token like `--count true`; passing a number with thousands separator or unit (`--timeout 10s`).","commonSituations":"Copy-pasting values from prose or docs; locale-formatted numbers (`1,5`); units accidentally included; agents guessing value formats.","solutions":["Pass a bare numeric literal: `--count 10`","Strip units/suffixes from the value","For unit-bearing quantities, check the verb help for the expected unit and convert first (e.g. `10s` → `--timeout 10000` if ms)"],"exampleFix":"# before\nncl tasks create --interval 30s ...\n# Error: --interval must be a number, got \"30s\"\n\n# after\nncl tasks create --interval 30 ...","handlingStrategy":"validation","validationCode":"if (typeof v === 'string' && Number.isNaN(Number(v))) throw new Error(`value for number flag is not numeric: ${v}`);","typeGuard":"function isNumericFlagValue(v: unknown): v is number | string {\n  return typeof v === 'number' || (typeof v === 'string' && !Number.isNaN(Number(v)) && v.trim() !== '');\n}","tryCatchPattern":"catch (e) { if (e instanceof Error && /must be a number/.test(e.message)) { /* coerce or re-ask */ } else throw e; }","preventionTips":["Normalize units before passing (10s → 10000 ms per the flag's documented unit)","Lint generated commands to ensure number flags get digit-only values"],"tags":["cli","argument-validation","type-coercion","number"],"backgroundTag":"invalid-argument-type","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}