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