{"record":{"id":"62249b2cc16bedd1","repo":"jackwener/OpenCLI","slug":"receipt-file-does-not-exist-receipt","errorCode":null,"errorMessage":"Receipt file does not exist: ${receipt}","messagePattern":"Receipt file does not exist: (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/mercury/utils.js","lineNumber":44,"sourceCode":"        const normalized = value.trim().toLowerCase();\n        if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) return true;\n        if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) return false;\n        throw new ArgumentError(`Boolean argument ${name} must be true or false`);\n    }\n    return fallback;\n}\n\nfunction parseReceiptPath(kwargs) {\n    const receipt = path.resolve(requireString(kwargs, 'receipt'));\n    let stat;\n    try {\n        stat = fs.statSync(receipt, { throwIfNoEntry: false });\n    }\n    catch (error) {\n        throw new ArgumentError(`Receipt file cannot be read: ${receipt}`, error instanceof Error ? error.message : undefined);\n    }\n    if (!stat || !stat.isFile()) {\n        throw new ArgumentError(`Receipt file does not exist: ${receipt}`);\n    }\n    return receipt;\n}\n\nfunction parseAmount(kwargs) {\n    const amount = requireString(kwargs, 'amount').replace(/,/g, '');\n    if (!/^\\d+(\\.\\d{1,2})?$/.test(amount) || Number(amount) <= 0) {\n        throw new ArgumentError(`Amount must be a positive number with up to two decimals: ${amount}`);\n    }\n    return amount;\n}\n\nfunction parseCurrency(kwargs) {\n    const currency = optionalString(kwargs, 'currency', 'CNY').toUpperCase();\n    if (!/^[A-Z]{3}$/.test(currency)) {\n        throw new ArgumentError(`Currency must be a three-letter ISO currency code: ${currency}`);\n    }\n    return currency;","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/mercury/utils.js#L26-L62","documentation":"After statSync succeeds (with throwIfNoEntry:false it returns undefined instead of throwing for missing entries), parseReceiptPath checks that a file exists AND is a regular file. If the path is missing, or resolves to a directory/special file, this ArgumentError is thrown. It is the 'not there or not a file' sibling of the read-failure error.","triggerScenarios":"receipt path does not exist; receipt points to a directory; receipt is a fifo/socket/device node; receipt is a dangling symlink (stat returns undefined).","commonSituations":"Typo in filename or extension (.pdf vs .PNG); file deleted or moved after being referenced in a script; passing a directory instead of the file; shell glob that expanded to nothing.","solutions":["Run ls -l on the path and confirm a regular file exists at that exact location.","Correct typos in the path/filename, or re-download/export the receipt file.","If you passed a directory, point at the specific receipt file inside it.","Add a pre-check in calling scripts: test -f \"$RECEIPT\" before invoking the command."],"exampleFix":"// before\n--receipt ./receipts            # directory\n// after\n--receipt ./receipts/receipt-2026-08-01.pdf","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nfunction receiptFileExists(p) {\n  const st = fs.statSync(p, { throwIfNoEntry: false });\n  return !!st && st.isFile();\n}","typeGuard":"function isExistingFile(p) {\n  try { return fs.statSync(p).isFile(); } catch { return false; }\n}","tryCatchPattern":"try {\n  await reimburse({ receipt });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('Receipt file does not exist')) {\n    const dir = path.dirname(e.message.split(': ')[1] ?? receipt);\n    console.error(`Receipt missing. Nearby files: ${fs.readdirSync(dir).join(', ')}`);\n  } else throw e;\n}","preventionTips":["Use shell completion or ls to confirm the exact filename before running","Check --receipt points to a file, not a directory","Regenerate/export the receipt if it was moved or cleaned up","Wrap scripts with [[ -f $RECEIPT ]] || exit 1 guards"],"tags":["argument-validation","filesystem","file-not-found","input"],"backgroundTag":"file-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}