Skip to content

Dangling transactions

As we learned in the step-by-step example, beanhub-import uses the import-id metadata to track which Beancount transactions were generated by the import engine. Every time you run the import command, the engine collects all existing transactions with import-id metadata from your Beancount files, compares them with the transactions it would generate from the current rules and input data, and computes the changes needed to bring everything up to date.

But what happens when a previously imported transaction no longer has a corresponding entry in the input data or the import rules? That transaction becomes dangling.

What causes dangling transactions

A dangling transaction is a Beancount transaction that has import-id and import-src metadata — meaning it was generated by beanhub-import — but the import engine can no longer find its source. This can happen in several situations:

  • A CSV file is deleted or moved. If you remove or rename an input CSV file, the transactions that were previously imported from it will no longer have a matching source.
  • The input matching pattern changes. If you modify the match pattern in your input config (e.g., changing from import-data/connect/chase/*.csv to a different path), previously matched files may no longer be included.
  • Rows are removed from a CSV file. If a bank re-exports a CSV file with fewer entries (for example, after a shorter time range is selected), some previously imported transactions may lose their source row.
  • The import rule is removed. If you delete a rule that was generating transactions, those already-generated transactions are left behind. This is different from changing the rule to ignore or del_txn.
  • The extractor changes. If you switch to a different extractor, the import-id values may change, causing the engine to no longer recognize the previously imported transactions.

How the import engine handles dangling transactions

The import engine does not automatically delete dangling transactions. This is by design. The engine only modifies transactions it can actively match — transactions that have a current rule generating or deleting them. If no rule references a particular import-id, the engine simply leaves that Beancount transaction alone.

This means dangling transactions will remain in your Beancount files silently. They won't cause errors, but they may lead to incorrect balances if the underlying data has changed.

How to identify dangling transactions

The easiest way to identify dangling transactions is to run the beanhub import command. The import engine automatically detects dangling transactions and displays them in a Dangling Transactions table in its output. Each entry in the table shows the file path, line number, and import-id of the dangling transaction, so you can quickly locate them in your Beancount files.

You can also spot them manually by looking for Beancount transactions that have import-id and import-src metadata but whose import-src points to a file that no longer exists or no longer contains the corresponding entry.

For example, if you see a transaction like this in your Beancount file:

2025-01-15 * "Sweetgreen" "DoorDash food delivery"
  import-id: "1lmOANutKCLWGfAmkkAfFdPvvU4GhQW"
  import-src: "import-data/connect/chase/2025.csv"
  Liabilities:ChaseCreditCard                           -61.94 USD
  Expenses:FoodDelivery:DoorDash                         61.94 USD

But the file import-data/connect/chase/2025.csv has been deleted or the transaction with that ID no longer exists in it, this transaction is dangling.

How to handle dangling transactions

There are a few approaches depending on your situation:

Keep the transaction as-is

If the transaction is still valid and you simply want to keep it as part of your books, you can remove the import-id and import-src metadata to turn it into a regular, manually maintained transaction. This way, the import engine will no longer consider it an imported transaction.

2025-01-15 * "Sweetgreen" "DoorDash food delivery"
  Liabilities:ChaseCreditCard                           -61.94 USD
  Expenses:FoodDelivery:DoorDash                         61.94 USD

Remove dangling transactions automatically

You can pass the --remove-dangling flag to the beanhub import command to automatically delete all dangling transactions from your Beancount files:

beanhub import --remove-dangling

Without this flag, dangling transactions are reported in the output but left untouched.

Delete the transaction manually

If the transaction should no longer exist, you can simply delete it from your Beancount file by hand.

Use del_txn before removing the source

If you know ahead of time that you're going to remove a CSV file or change your input patterns, you can add a del_txn rule first to clean up the imported transactions before making the change. Run the import command to apply the deletions, and then proceed with removing the source files or updating the input config.

Preventing dangling transactions

The best way to avoid dangling transactions is to be mindful when making changes to your input configuration:

  • Don't delete CSV files that have already been imported. Keep your input CSV files around, even old ones. They don't take much space, and the import engine will simply skip the already-processed entries.
  • Use del_txn or ignore before removing rules. If you're removing a rule that previously generated transactions, first change its action to del_txn, run the import to clean up, and then remove the rule (or change it to ignore if the transactions still appear in the input).
  • Be careful when changing input paths. If you reorganize your file structure, make sure the import engine can still find all the previously imported source files, or clean up the corresponding transactions first.

By keeping these practices in mind, you can maintain a clean and accurate Beancount book without unexpected leftover entries.