Skip to content

Breaking Changes: v2 to v3 ​

Overview ​

This document lists all breaking changes between Beancount v2 and v3. Most changes are minor and affect edge cases.

Note: This document has been validated against beancount 3.2.0 (January 2025).

Syntax Changes ​

None ​

The core syntax is unchanged. All valid v2 directives parse in v3.

Option Changes ​

Removed Options ​

OptionReasonAlternative
experiment_explicit_tolerancesNow default behaviorRemove option
encodingUTF-8 only in v3Convert files to UTF-8

Deprecated Options (Still Work) ​

OptionStatusNotes
allow_deprecated_none_for_tags_and_linksDeprecatedProduces warning, still accepted

Type Changes ​

Optionv2 Typev3 Type
operating_currencyStringList of strings

Unchanged Options ​

The following options use the same names in v3 as in v2:

  • name_assets - Root name for asset accounts (default: "Assets")
  • name_liabilities - Root name for liability accounts (default: "Liabilities")
  • name_equity - Root name for equity accounts (default: "Equity")
  • name_income - Root name for income accounts (default: "Income")
  • name_expenses - Root name for expense accounts (default: "Expenses")

Plugin Changes ​

Plugin Path Changes ​

v2 Pathv3 PathStatus
beancount.plugins.autobeancount.plugins.auto_accountsBoth work (aliased)
beancount.plugins.pricesbeancount.plugins.implicit_pricesBreaking: Only v3 path works
beancount.plugins.check_closingbeancount.plugins.close_treeBoth work (aliased)

Only beancount.plugins.prices is a true breaking change.

Removed Plugins ​

PluginReasonAlternative
beancount.plugins.fill_accountRarely usedCustom plugin
beancount.plugins.tag_pendingSupersededUse metadata

Plugin API Changes ​

Options Map ​

python
# v2: operating_currency was a single string
currency = options_map['operating_currency']

# v3: operating_currency is a list
currencies = options_map['operating_currency']

Plugin Signature ​

python
# v2: Optional config parameter
def my_plugin(entries, options_map, config=None):
    pass

# v3: Same, but config parsing standardized
def my_plugin(entries, options_map, config=None):
    # Config is always a string if provided
    pass

Semantic Changes ​

Tolerance Calculation ​

v2: Multiple tolerance modes, configurable.

v3: Single standardized mode:

tolerance = 0.5 * 10^(-precision)

Where precision is the maximum decimal places used in the transaction.

Impact: Some transactions that balanced in v2 may not balance in v3, or vice versa.

Example:

beancount
; For 2 decimal places, tolerance = 0.005 USD
; 0.004 imbalance - PASSES
2024-01-15 * "Within tolerance"
  Expenses:Food      10.00 USD
  Assets:Checking   -10.004 USD

; 0.01 imbalance - FAILS
2024-01-15 * "Outside tolerance"
  Expenses:Food      10.00 USD
  Assets:Checking   -10.01 USD

Booking Method Case ​

v2: Case-insensitive booking methods.

v3: Case-sensitive, uppercase required.

beancount
; v2 (worked)
2024-01-01 open Assets:Stock AAPL "fifo"

; v3 (required)
2024-01-01 open Assets:Stock AAPL "FIFO"

Valid booking methods: STRICT, FIFO, LIFO, HIFO, AVERAGE, NONE

Balance Assertion Timing ​

v2: Checked at end of day.

v3: Checked at start of day (before same-day transactions).

Impact: Assertions may need date adjustment:

beancount
2024-01-15 * "Deposit"
  Assets:Checking  100 USD
  Income:Salary   -100 USD

; v3: This checks balance BEFORE the deposit
; Asserts 0 USD (starting balance) - PASSES
2024-01-15 balance Assets:Checking 0 USD

; v3: To check AFTER same-day transactions, use next day
2024-01-16 balance Assets:Checking 100 USD

Empty Cost Specification ​

v2: {} sometimes inferred cost from context.

v3: {} strictly means "use booking method."

beancount
; v2: Might infer cost
Assets:Stock -10 AAPL {}

; v3: Always uses booking method (FIFO, LIFO, etc.)
Assets:Stock -10 AAPL {}

Error Handling ​

Error Types ​

Beancount 3.x uses Python exception classes:

Error ClassDescription
ParserErrorSyntax and parsing errors
ValidationErrorSemantic validation errors
DeprecatedErrorDeprecated feature warnings

Error Format ​

Errors are Python objects with structured data:

python
ValidationError(
    source={'filename': 'ledger.beancount', 'lineno': 42},
    message="Invalid reference to unknown account 'Assets:Unknown'",
    entry=<Transaction object>
)

File Handling Changes ​

Encoding ​

v2: Multiple encodings supported via option.

v3: UTF-8 only.

beancount
; v2 (worked)
option "encoding" "latin-1"

; v3 (removed - produces error)
; Convert files to UTF-8

Include Path Resolution ​

v2: Some edge cases in relative path handling.

v3: Strictly relative to including file's directory.

BOM Handling ​

v2: BOM sometimes caused issues.

v3: UTF-8 BOM explicitly ignored.

Query Language Changes ​

BQL Syntax ​

No breaking changes. All v2 queries work in v3.

New Functions ​

v3 adds new BQL functions (non-breaking):

  • root(account, n) - Get first n components
  • leaf(account) - Get last component
  • parent(account) - Get parent account

Date Handling ​

Date Format ​

No change: YYYY-MM-DD and YYYY/MM/DD both supported.

Directive Ordering ​

v2: Implementation-defined ordering for same-date directives.

v3: Specified ordering:

  1. Balance assertions first
  2. Other directives by file order

Compatibility Matrix ​

Featurev2v3Action
Core syntaxYYNone
Old option namesYYNone needed
beancount.plugins.pricesYNUpdate to implicit_prices
Lowercase booking methodsYNUppercase
Non-UTF8 filesYNConvert to UTF-8
operating_currency as stringYNHandle as list

Legend: Y = Works, N = Error