{"record":{"id":"21cfd8219bfc8e13","repo":"jackwener/OpenCLI","slug":"ocr-wait-seconds-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"ocr-wait-seconds must be a non-negative integer: ${raw}","messagePattern":"ocr-wait-seconds must be a non-negative integer: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/mercury/utils.js","lineNumber":84,"sourceCode":"    const date = requireString(kwargs, 'date');\n    const match = date.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n    if (!match) {\n        throw new ArgumentError(`Date must be YYYY-MM-DD: ${date}`);\n    }\n    const year = Number(match[1]);\n    const month = Number(match[2]);\n    const day = Number(match[3]);\n    const parsed = new Date(Date.UTC(year, month - 1, day));\n    if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {\n        throw new ArgumentError(`Date must be a real calendar date: ${date}`);\n    }\n    return date;\n}\n\nfunction parseOcrWaitSeconds(kwargs) {\n    const raw = optionalString(kwargs, 'ocr-wait-seconds', '8');\n    if (!/^\\d+$/.test(raw)) {\n        throw new ArgumentError(`ocr-wait-seconds must be a non-negative integer: ${raw}`);\n    }\n    return Number(raw);\n}\n\nexport function normalizeReimbursementInput(kwargs) {\n    return {\n        receipt: parseReceiptPath(kwargs),\n        amount: parseAmount(kwargs),\n        currency: parseCurrency(kwargs),\n        date: parseDate(kwargs),\n        merchant: requireString(kwargs, 'merchant'),\n        category: optionalString(kwargs, 'category', 'Marketing & Advertising'),\n        notes: requireString(kwargs, 'notes'),\n        ocrWaitSeconds: parseOcrWaitSeconds(kwargs),\n        closeAfterReview: optionalBoolean(kwargs, 'close-after-review', false),\n    };\n}\n","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/utils.js#L66-L102","documentation":"parseOcrWaitSeconds reads the optional ocr-wait-seconds setting (default '8') and requires it to be all digits (^\\d+$), i.e. a non-negative integer. Negatives, decimals, negatives-of-zero variants, empty strings, or non-numeric text throw this ArgumentError; the validated value is returned as a Number.","triggerScenarios":"--ocr-wait-seconds '-1', '2.5', 'eight', '', '+8', or '8s' — anything not purely digits.","commonSituations":"Users expressing durations with units ('30s', '1m'); copying decimal timeouts from config files; environment placeholders that failed to expand leaving empty or templated text; negative values intended as 'no wait'.","solutions":["Pass a plain non-negative integer: --ocr-wait-seconds 30.","Convert durations to seconds yourself (1m -> 60) before passing.","Restore the default by omitting the option (defaults to 8 seconds).","If sourced from env, verify the variable is set and contains digits: echo \"$OCR_WAIT\"."],"exampleFix":"// before\n--ocr-wait-seconds \"1m\"\n// after\n--ocr-wait-seconds \"60\"","handlingStrategy":"validation","validationCode":"function isValidWaitSeconds(v) {\n  return /^\\d+$/.test(String(v));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await reimburse({ 'ocr-wait-seconds': wait });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('ocr-wait-seconds')) {\n    console.error('Provide a whole number of seconds, e.g. --ocr-wait-seconds 30');\n  } else throw e;\n}","preventionTips":["Express durations in plain seconds without units","Verify env placeholders expanded before invoking","Omit the option to use the built-in default (8)","Coerce with parseInt and re-check Number.isInteger upstream"],"tags":["argument-validation","input-validation","cli","timeout"],"backgroundTag":"invalid-input-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}