{"record":{"id":"ec24098d0134963d","repo":"tinyhumansai/openhuman","slug":"label-must-be-a-non-negative-number","errorCode":null,"errorMessage":"${label} must be a non-negative number","messagePattern":"(.+?) must be a non-negative number","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/debug/harness-cache-audit.mjs","lineNumber":152,"sourceCode":"\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() {\n  return process.env.OPENHUMAN_APP_ENV === \"staging\"\n    ? path.join(homedir(), \".openhuman-staging\")\n    : path.join(homedir(), \".openhuman\");\n}\n\nasync function defaultWorkspace() {\n  if (process.env.OPENHUMAN_WORKSPACE) return process.env.OPENHUMAN_WORKSPACE;\n  const openhumanDir = defaultOpenhumanDir();\n  try {\n    const active = await readFile(\n      path.join(openhumanDir, \"active_user.toml\"),\n      \"utf8\",\n    );\n    const match = active.match(/^\\s*user_id\\s*=\\s*\"([^\"]+)\"\\s*$/m);","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/debug/harness-cache-audit.mjs#L134-L170","documentation":"parseNonNegativeNumber() accepts any finite number >= 0 (fractions allowed) and throws with the label otherwise. In harness-cache-audit.mjs it guards --min-hit-rate, the aggregate cached/input ratio threshold in percent below which the audit exits non-zero. Non-numeric strings become NaN and fail Number.isFinite; negatives fail the < 0 check.","triggerScenarios":"`--min-hit-rate -5`, `--min-hit-rate abc`, `--min-hit-rate 20%` (trailing % makes it NaN), `--min-hit-rate Infinity` (not finite); an unset env var interpolated as the bare text of the flag's value in a wrapper.","commonSituations":"Percent sign copied along with the number; comma decimal (`0,5`); intending a ratio (0.2) where a percent (20) is expected — legal but semantically off, so the audit silently passes/fails unexpectedly; wrapper variable typos.","solutions":["Pass a plain percent number: `--min-hit-rate 20` for 20%","Drop the % sign and any units","Remember the unit is percent, not a 0-1 ratio","Guard wrappers with a numeric regex before composing the command"],"exampleFix":"# before\nnode scripts/debug/harness-cache-audit.mjs --min-hit-rate 20%\n# Error: --min-hit-rate must be a non-negative number\n\n# after\nnode scripts/debug/harness-cache-audit.mjs --min-hit-rate 20","handlingStrategy":"validation","validationCode":"const toNonNegativeNumber = (raw, label) => {\n  const n = Number(raw);\n  if (!Number.isFinite(n) || n < 0) {\n    console.error(`${label} must be a number >= 0, no % or units (got: ${raw})`);\n    process.exit(2);\n  }\n  return n;\n};\nconst minHitRate = toNonNegativeNumber(process.env.MIN_HIT_RATE ?? \"1\", \"--min-hit-rate\");","typeGuard":"const isNonNegativeNumberString = (s) => /^\\d+(\\.\\d+)?$/.test(String(s).trim());","tryCatchPattern":null,"preventionTips":["The unit of --min-hit-rate is percent: pass 20, not 0.2 and not 20%","Strip % and units when copying thresholds from dashboards or notes"],"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"}