title: Error Codes Reference description: Validation errors and how to fix them
Error Codes Reference
This page documents validation errors that rledger check can report.
Error Format
Errors are displayed as:
file.beancount:42: error[E1001]: Account not openedFormat: file:line: error[code]: message
Error Code Categories
| Range | Category |
|---|---|
| E1xxx | Account errors |
| E2xxx | Balance errors |
| E3xxx | Transaction errors |
| E4xxx | Booking/lot errors |
| E5xxx | Currency errors |
| E6xxx | Metadata errors |
| E7xxx | Option errors |
| E8xxx | Document errors |
| E10xxx | Date warnings/info |
| E11xxx | Budget errors |
Account Errors (E1xxx)
E1001: Account Not Opened
Cause: Transaction uses an account without an open directive.
Example:
; No 'open' for Expenses:Food
2024-01-15 * "Coffee"
Expenses:Food 5.00 USD
Assets:Cash -5.00 USDFix: Add an open directive:
2020-01-01 open Expenses:Food
2020-01-01 open Assets:Cash USDOr use rledger doctor missing-open to generate them.
E1002: Account Already Open
Cause: Duplicate open directive for same account.
Fix: Remove the duplicate open directive.
E1003: Account Used After Close
Cause: Transaction on an account after its close date.
Example:
2024-01-01 close Assets:OldBank
2024-02-15 * "Late transaction"
Assets:OldBank 100.00 USD ; Account is closedFix: Use correct account or adjust close date.
E1004: Account Close With Non-Zero Balance (Warning)
Cause: Closing an account that still has a balance.
Fix: Zero out the account balance before closing.
E1005: Invalid Account Name
Cause: Account name doesn't match required format.
Example:
2024-01-15 * "Coffee"
expenses:food 5.00 USD ; Lowercase not allowedFix: Use Title:Case:Accounts starting with Assets, Liabilities, Equity, Income, or Expenses.
Balance Errors (E2xxx)
E2001: Balance Assertion Failed
Cause: Account balance doesn't match assertion.
Example:
2024-01-15 balance Assets:Checking 1000.00 USD
; But actual balance is 950.00 USDFix:
- Check for missing transactions
- Verify the expected amount
- Use
rledger doctor contextto see surrounding transactions
E2002: Balance Exceeds Tolerance
Cause: Balance is off by more than the allowed tolerance.
Fix: Adjust the balance assertion or find the discrepancy.
E2003: Pad Without Balance Assertion
Cause: A pad directive has no subsequent balance assertion.
Fix: Add a balance assertion after the pad.
E2004: Multiple Pads for Same Balance
Cause: Multiple pad directives for the same balance assertion.
Fix: Remove duplicate pad directives.
Transaction Errors (E3xxx)
E3001: Transaction Does Not Balance
Cause: Postings don't sum to zero.
Example:
2024-01-15 * "Coffee"
Expenses:Food 5.00 USD
Assets:Cash -4.00 USD ; Doesn't balanceFix: Ensure postings sum to zero:
2024-01-15 * "Coffee"
Expenses:Food 5.00 USD
Assets:Cash -5.00 USDE3002: Multiple Missing Amounts
Cause: More than one posting is missing an amount for the same currency.
Fix: Only one posting per currency can have an inferred amount.
E3003: Transaction Has No Postings
Cause: Transaction has no posting lines.
Fix: Add at least two postings to the transaction.
E3004: Transaction Has Single Posting (Warning)
Cause: Transaction has only one posting line.
Fix: Add a second posting to complete the transaction.
Booking Errors (E4xxx)
E4001: No Matching Lot
Cause: Can't find a lot to reduce when selling/removing inventory.
Example:
2024-01-15 * "Sell AAPL"
Assets:Brokerage -10 AAPL {150.00 USD} ; No lot at this costFix: Check cost basis matches existing lot, or use {} for automatic matching.
A {*} merge reports it too when the spec states something the merged pool is not. {*} computes the pool's cost, so a cost beside it is checked as a claim: it must be the pool's cost rounded to the decimal places written ({*, 106.67 USD} for a pool of 106.666… USD), a total or compound cost must be what the units sold cost at that price, and a currency must be the pool's. A date or label is an error, because the merged lot has neither.
A {*} on a posting that reduces no lot is reported as well: a buy, a sale from an account holding nothing, or any sale in an account booked NONE. {*} merges the pool and then sells from it, so where nothing is sold there is no pool to merge. Remove the *; to keep an account at its average cost, book it AVERAGE. A {*} must also write its units (-5 X {*}, not X {*}): the merge runs while booking, before interpolation could solve them. Beancount refuses every {*} (Cost merging is not supported yet).
E4002: Insufficient Units
Cause: Trying to reduce more units than available in the lot.
Fix: Check the quantity being sold matches available holdings.
E4003: Ambiguous Lot Match
Cause: In STRICT booking mode, multiple lots could match.
Fix: Specify the exact lot using cost basis {cost} or date {date}.
BOOK: Cannot Infer Currency
Cause: A posting writes a number but no currency (Assets:Cash 42.50), and nothing determines which currency it is in. Reported as interpolation failed: cannot infer currency for posting to account Expenses:Food (for the example below). rledger reads the currency the same way Python beancount does, in this order:
- If the posting has no cost and no price, is the only posting in the transaction whose currency is still open, and every other posting is in one currency, it takes that currency.
- Otherwise it takes the currency the account already holds, if the account held exactly one currency before this transaction.
Neither an open directive's currency list nor a pad counts: pads are expanded after booking, so an account funded only by a pad holds nothing yet. The currency the transaction is out of balance in is not used either.
Example:
2024-01-01 open Assets:Cash
2024-01-01 open Expenses:Food
2024-01-15 * "Lunch"
Expenses:Food 12.50 ; Expenses:Food holds nothing yet
Assets:CashFix: Write the currency (12.50 USD). A posting with a cost or price (-5 {300 USD}) can only take its commodity from the account, because the cost or price names its own currency, not the commodity being counted.
E4005: Negative Cost
Cause: A cost specification resolves to a negative amount.
Fix: Ensure cost values are non-negative (e.g., {10 USD} not {-10 USD}). Zero cost is allowed.
Currency Errors (E5xxx)
E5001: Currency Not Declared
Cause: Using a currency without a commodity directive (when strict mode enabled).
Fix: Declare the currency:
2020-01-01 commodity USDE5002: Currency Not Allowed in Account
Cause: Posting uses currency not allowed for account.
Example:
2020-01-01 open Assets:Bank USD ; Only USD allowed
2024-01-15 * "Deposit"
Assets:Bank 100.00 EUR ; EUR not allowedFix: Use allowed currency or update account declaration.
E5003: Invalid Precision Metadata (Warning)
Cause: A commodity directive has invalid precision metadata.
Fix: Correct the precision metadata value on the commodity directive.
Budget Errors (E11xxx)
E11001: Malformed Budget Directive (Warning)
A custom "budget" directive has Fava's shape but carries content rledger cannot use, so rledger report budget ignores it.
2024-01-01 custom "budget" Expenses:Food "fortnightly" 400.00 USD ; not an interval keyword
2024-01-01 custom "budget" Expenses:Food "monthly" 400.00 USD 300.00 EUR ; two amountsFix: use one of daily, weekly, monthly, quarterly or yearly (each also accepted as the bare noun), and write one budget per directive.
Only directives rledger is confident are budgets get reported. Ownership is one rule: a real interval keyword in the interval slot, or an account and an amount in a payload short enough to be Fava's. A custom "budget" meeting neither is NOT flagged: custom is beancount's open extension point and the name is not rledger's alone — beancount's own documented example is custom "budget" "weekly < 1000.00 USD" 2016-02-28 TRUE 43.03 USD 23. rledger report budget still reports those, because a user who asked about budgets is owed the news that one could not be read.
Option Errors (E7xxx)
E7001: Unknown Option
Cause: Unrecognized option name.
Fix: Check option spelling. Use rledger doctor list-options to see valid options.
E7002: Invalid Option Value
Cause: Option value is invalid.
Fix: Check the expected format for the option.
E7003: Duplicate Option
Cause: Non-repeatable option specified multiple times. The last value wins, matching bean-check, so this is a warning rather than an error.
Fix: Remove duplicate option directives, or rely on the last one deliberately.
E7009: Option in an Included File Is Ignored
Cause: An option was set in an included file rather than the top-level ledger. Most options are taken from the top-level file only, so the included value has no effect.
Options that describe the file declaring them still apply from anywhere: operating_currency, documents, insert_pythonpath, display_precision, and plugin directives. Everything else, notably booking_method and inferred_tolerance_default, comes from the top-level ledger, so a sub-ledger cannot change how the whole tree books or what counts as balanced.
Fix: Move the option to the top-level ledger if it should govern, or remove it if the sub-ledger only needed it when loaded standalone.
E7010: Account Option Written as a Full Name
Cause: An account-name option (account_previous_*, account_current_*) starts with one of the ledger's root names, e.g. option "account_previous_balances" "Equity:Opening-Balances". These options are leaf names under the equity root, as beancount defines them, so the root is joined on and the value names Equity:Equity:Opening-Balances, in rustledger and in beancount alike. It is a warning because the value is legal; it is almost always the full-name form rustledger used to require.
Fix: Drop the root: option "account_previous_balances" "Opening-Balances". The warning says so only when the root is the equity root. A value that is the root itself ("Equity"), or that starts with another root ("Income:Oops"), has no leaf form: these options can only name accounts under equity.
E7007: Option Accepted but Has No Effect
Cause: A recognized Beancount option is parsed for compatibility but is intentionally a no-op in rustledger. Currently this applies to account_rounding: Beancount uses it to absorb the residual created when an interpolated leg is rounded and the rounding breaks the sum, but rustledger preserves full precision during interpolation (it never rounds a non-zero residual to zero), so no rounding residual is ever produced and there is nothing for a rounding account to catch.
Fix: None required — the option is harmless. Remove it if you want the warning to go away.
Document Errors (E8xxx)
E8001: Document Not Found / Plugin Not Found
Cause: A document directive references a missing file, or a plugin name does not match any built-in, WASM, or resolvable Python plugin.
Fix: Ensure the document file exists at the specified path; for plugins, check the name against the Plugins Reference.
E8002: Plugin Execution Failed
Cause: A plugin file was found but failed to load or run (e.g. a Python plugin raised, or its runtime could not be initialized). The message carries the underlying error.
Fix: Read the embedded error. For Python plugins, ensure the file is self-contained (the sandbox cannot see your virtualenv).
E8004: Python Plugin Referenced by Module Name
Cause: A custom Python plugin was referenced by module name (e.g. plugin "mypackage.mymodule"). rustledger does not search the system Python path, so only file-path references load.
Fix: Reference the .py file directly — e.g. plugin "/abs/path/to/mymodule.py". See Referencing a Python Plugin.
E8005: Python Plugin Requires Feature
Cause: A Python plugin was referenced in a build without the python-plugins feature.
Fix: Use a build with Python plugin support, or switch to a native/WASM plugin.
Date Warnings (E10xxx)
E10002: Entry Dated in Future (Warning)
Cause: Entry has a date in the future.
Note: This is a warning that may indicate a typo.
Using Error Information
Find Context
# See what's around an error
rledger doctor context ledger.beancount 42Check Specific Account
# View account history
rledger query ledger.beancount \
"SELECT date, narration, position WHERE account = 'Assets:Bank' ORDER BY date"Generate Missing Opens
# Auto-generate open directives
rledger doctor missing-open ledger.beancountSee Also
- check command - Running validation
- doctor command - Debugging tools
- Plugins - Plugin-specific errors