{"record":{"id":"fe382856999a25ac","repo":"tinyhumansai/openhuman","slug":"label-must-be-a-positive-integer-fe3828","errorCode":null,"errorMessage":"${label} must be a positive integer","messagePattern":"(.+?) must be a positive integer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/debug/harness-cache-audit.mjs","lineNumber":138,"sourceCode":"        break;\n      case \"--verbose\":\n        opts.verbose = true;\n        break;\n      case \"-h\":\n      case \"--help\":\n        console.log(usage());\n        process.exit(0);\n      default:\n        throw new Error(`unknown option: ${arg}`);\n    }\n  }\n  return opts;\n}\n\nfunction parsePositiveInt(raw, label) {\n  const value = Number(raw);\n  if (!Number.isInteger(value) || value < 1)\n    throw new Error(`${label} must be a positive integer`);\n  return value;\n}\n\nfunction parseNonNegativeInt(raw, label) {\n  const value = Number(raw);\n  if (!Number.isInteger(value) || value < 0)\n    throw new Error(`${label} must be a non-negative integer`);\n  return value;\n}\n\nfunction parseNonNegativeNumber(raw, label) {\n  const value = Number(raw);\n  if (!Number.isFinite(value) || value < 0)\n    throw new Error(`${label} must be a non-negative number`);\n  return value;\n}\n\nfunction defaultOpenhumanDir() {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/debug/harness-cache-audit.mjs#L120-L156","documentation":"parsePositiveInt() coerces the raw string with Number() and requires an integer >= 1; otherwise it throws with the flag's label. In harness-cache-audit.mjs it guards --turns and --rpc-timeout-ms. It exists because zero/negative/fractional values for these knobs are nonsensical (a zero-turn audit or a zero-ms timeout would hang or trivially abort every RPC).","triggerScenarios":"`--turns 0` (zero turns), `--turns 3.5`, `--turns abc` (Number() → NaN fails Number.isInteger), `--rpc-timeout-ms 0`, `--rpc-timeout-ms 10_000` (underscore is not numeric in Number()), or scientific-notation strings like `1e3` — technically valid to Number() but usually a typo intent.","commonSituations":" Trying to disable something by setting it to 0; paste from docs with underscores; locale decimal comma (3,5 → parsed as 3 then trailing garbage or NaN); math in shell like `--turns $((2+2))` producing empty on error.","solutions":["Pass a plain integer >= 1: `--turns 4`, `--rpc-timeout-ms 900000`","For 'as fast as possible' use 1, not 0","Remove underscores/commas/units from the value","Echo the variable in wrappers before composing the command to catch empty expansions"],"exampleFix":"# before\nnode scripts/debug/harness-cache-audit.mjs --turns 0\n# Error: --turns must be a positive integer\n\n# after\nnode scripts/debug/harness-cache-audit.mjs --turns 1","handlingStrategy":"validation","validationCode":"const toPositiveInt = (raw, label) => {\n  const n = Number(raw);\n  if (!Number.isInteger(n) || n < 1) {\n    console.error(`${label} must be an integer >= 1 (got: ${raw})`);\n    process.exit(2);\n  }\n  return n;\n};\nconst turns = toPositiveInt(process.env.AUDIT_TURNS ?? \"3\", \"--turns\");","typeGuard":"const isPositiveIntString = (s) => /^[1-9]\\d*$/.test(String(s).trim());","tryCatchPattern":null,"preventionTips":["Write thresholds as plain decimal integers; no underscores, commas, units, or percent signs","Remember 0 is invalid for --turns/--rpc-timeout-ms but valid for --max-turns-without-cache — the two validators differ"],"tags":["cli","validation","numeric-parsing"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}