payable-receipt-ocr
Reference

Errors and CLI Exits

Controlled error classes, error codes, CLI exit codes, and when each is raised.

Error hierarchy

All controlled errors inherit from ReceiptOcrError. Catching the base class handles every controlled failure:

from payable_receipt_ocr.errors import (
    ReceiptOcrError,       # base class
    InputFileError,        # exit 3
    UnsupportedImageError, # exit 4
    ConfigurationError,    # exit 5
    RuntimeBaselineError,  # exit 5 (subclass of ConfigurationError)
    OcrEngineError,        # exit 6
)

Error reference

ClassCodeCLI exitWhen raised
InputFileErrorinput_file3Image path does not exist or is not readable
UnsupportedImageErrorunsupported_image4Unsupported format; file > 10 MiB; decoded > 12 MP
ConfigurationErrorconfiguration5Invalid currency or runtime_policy argument
RuntimeBaselineErrorruntime_baseline5Tesseract not found; missing models; checksum mismatch; or conformant policy + runtime mismatch
OcrEngineErrorocr_engine6All OCR passes failed or none completed before the deadline
Unexpected1Unhandled exception (CLI only)

RuntimeBaselineError is a subclass of ConfigurationError and shares exit code 5.

CLI exit codes

Exit codeMeaning
0Success — JSON result on stdout
1Unexpected error (defensive catch-all)
3input_file error
4unsupported_image error
5configuration or runtime_baseline error
6ocr_engine error

On error, the CLI prints to stderr in the format:

payable-receipt-ocr [error_code]: human-readable message

No JSON is printed to stdout on error.

Holdout evaluator exit codes (separate contract)

tools/holdout/evaluate.py uses additional exit codes that are not part of the main CLI contract:

Exit codeMeaning
0Gate passed
1Gate failed (accuracy thresholds not met)
2Manifest parse error

Python error handling

InputFileError

try:
    result = recognize("missing.png", currency="INR")
except InputFileError as e:
    # e.code == "input_file"
    # e.exit_code == 3
    print(f"Cannot read file: {e}")

Raised when the path does not resolve to a readable file. Resolution happens before any OCR.

UnsupportedImageError

try:
    result = recognize("huge.png", currency="INR")
except UnsupportedImageError as e:
    print(f"Image outside supported scope: {e}")

Raised when:

  • The file format is not JPG, JPEG, PNG, or WebP
  • The file size exceeds 10 MiB
  • The decoded source exceeds 12 megapixels

ConfigurationError

try:
    result = recognize("receipt.png", currency="USD")
except ConfigurationError as e:
    print(f"Configuration invalid: {e}")

Raised when currency is not "INR" or runtime_policy is not "development" or "conformant".

RuntimeBaselineError

from payable_receipt_ocr.errors import RuntimeBaselineError

try:
    result = recognize("receipt.png", currency="INR")
except RuntimeBaselineError as e:
    # Tesseract missing, model issue, or conformant policy + runtime mismatch
    print(f"Runtime baseline error: {e}")
    # Run ./scripts/setup-models.sh to install correct models

OcrEngineError

from payable_receipt_ocr.errors import OcrEngineError

try:
    result = recognize("receipt.png", currency="INR")
except OcrEngineError as e:
    print(f"All OCR passes failed or the deadline was reached: {e}")

Raised when every scheduled pass fails, or when no pass completes before the deadline.

Checking the error code

All ReceiptOcrError subclasses expose a code attribute (stable string) and an exit_code attribute (integer). These are safe to branch on:

try:
    result = recognize("receipt.png", currency="INR")
except ReceiptOcrError as e:
    if e.code == "runtime_baseline":
        # guide user to run setup-models.sh
        pass
    elif e.code == "input_file":
        # file selection error
        pass
    else:
        # fallback
        pass

On this page