jackwener/OpenCLI · error · ArgumentError

Receipt file does not exist: ${receipt}

Error message

Receipt file does not exist: ${receipt}

What it means

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.

Source

Thrown at clis/mercury/utils.js:44

        const normalized = value.trim().toLowerCase();
        if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) return true;
        if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) return false;
        throw new ArgumentError(`Boolean argument ${name} must be true or false`);
    }
    return fallback;
}

function parseReceiptPath(kwargs) {
    const receipt = path.resolve(requireString(kwargs, 'receipt'));
    let stat;
    try {
        stat = fs.statSync(receipt, { throwIfNoEntry: false });
    }
    catch (error) {
        throw new ArgumentError(`Receipt file cannot be read: ${receipt}`, error instanceof Error ? error.message : undefined);
    }
    if (!stat || !stat.isFile()) {
        throw new ArgumentError(`Receipt file does not exist: ${receipt}`);
    }
    return receipt;
}

function parseAmount(kwargs) {
    const amount = requireString(kwargs, 'amount').replace(/,/g, '');
    if (!/^\d+(\.\d{1,2})?$/.test(amount) || Number(amount) <= 0) {
        throw new ArgumentError(`Amount must be a positive number with up to two decimals: ${amount}`);
    }
    return amount;
}

function parseCurrency(kwargs) {
    const currency = optionalString(kwargs, 'currency', 'CNY').toUpperCase();
    if (!/^[A-Z]{3}$/.test(currency)) {
        throw new ArgumentError(`Currency must be a three-letter ISO currency code: ${currency}`);
    }
    return currency;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Run ls -l on the path and confirm a regular file exists at that exact location.
  2. Correct typos in the path/filename, or re-download/export the receipt file.
  3. If you passed a directory, point at the specific receipt file inside it.
  4. Add a pre-check in calling scripts: test -f "$RECEIPT" before invoking the command.

Example fix

// before
--receipt ./receipts            # directory
// after
--receipt ./receipts/receipt-2026-08-01.pdf
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
function receiptFileExists(p) {
  const st = fs.statSync(p, { throwIfNoEntry: false });
  return !!st && st.isFile();
}

Type guard

function isExistingFile(p) {
  try { return fs.statSync(p).isFile(); } catch { return false; }
}

Try / catch

try {
  await reimburse({ receipt });
} catch (e) {
  if (e instanceof ArgumentError && e.message.startsWith('Receipt file does not exist')) {
    const dir = path.dirname(e.message.split(': ')[1] ?? receipt);
    console.error(`Receipt missing. Nearby files: ${fs.readdirSync(dir).join(', ')}`);
  } else throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/62249b2cc16bedd1. Report an issue: GitHub.