actualbudget/actual · error
Account mismatch: transaction belongs to account ${transacti
Error message
Account mismatch: transaction belongs to account ${transaction.account}, not ${accountId} What it means
moveTransaction validates that the accountId you pass in matches the account the transaction actually belongs to. The sort-order recalculation it performs is scoped to a single account, so moving a transaction while claiming it belongs to a different account would corrupt sibling ordering. The library throws this error immediately when transaction.account !== accountId.
Source
Thrown at packages/loot-core/src/server/transactions/app.ts:87
async function moveTransaction({
id,
accountId,
targetId,
}: {
id: string;
accountId: string;
targetId: string | null;
}) {
// Fetch the transaction to validate it exists and verify account
const transaction = await db.getTransaction(id);
if (!transaction) {
throw new Error(`Transaction not found: ${id}`);
}
// Validate that the provided accountId matches the transaction's actual account
// This prevents sort order calculations against the wrong account
if (transaction.account !== accountId) {
throw new Error(
`Account mismatch: transaction belongs to account ${transaction.account}, not ${accountId}`,
);
}
// Child transactions can be reordered within their parent's children
// The db.moveTransaction handles the sibling-scoped reordering for children
await db.moveTransaction(id, accountId, targetId);
return {};
}
async function parseTransactionsFile({
filepath,
options,
}: {
filepath: string;
options: ParseFileOptions;
}) {View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-fetch the transaction and pass its actual account as accountId when calling moveTransaction.
- If the intent is to move the transaction to a different account, do that first (update the transaction's account), then call moveTransaction with the new accountId.
- Check the client for stale state — refresh the transaction list after any account reassignment before reordering.
- Log both transaction.account and accountId at the call site to confirm which is wrong.
Example fix
// before
await moveTransaction({ id: txId, accountId: targetAccountId });
// after
const tx = await getTransaction(txId);
if (tx.account !== targetAccountId) {
await updateTransaction(txId, { account: targetAccountId });
}
await moveTransaction({ id: txId, accountId: tx.account }); Defensive patterns
Strategy: validation
Validate before calling
const tx = await getTransaction(id);
if (tx.account !== accountId) {
throw new Error(`Cannot move: transaction is in ${tx.account}, not ${accountId}`);
} Type guard
function canMove(tx: { account: string }, accountId: string): boolean {
return tx.account === accountId;
} Try / catch
try {
await moveTransaction({ id, accountId });
} catch (e) {
if (e.message.startsWith('Account mismatch:')) {
await refreshTransactions(); // reload stale state
} else { throw e; }
} Prevention
- Always source accountId from the freshly fetched transaction, not cached UI state
- Refresh the transaction list after any account reassignment
- Never pass a 'destination' account to moveTransaction; it expects the current account
When it happens
Trigger: Calling moveTransaction with an accountId that differs from the account stored on the transaction row — e.g. a stale accountId from a previous fetch, passing a destination account instead of the transaction's current account, or an off-by-one/wrong-row selection in a drag-and-drop reorder UI.
Common situations: UI bugs where a transaction was just reassigned to another account but the client caches the old accountId; concurrent edits where one client moves a transaction between accounts while another reorders it; tests hard-coding an accountId.
Related errors
- `date` is required when adding a transaction
- Amount is invalid, must be an integer: ${trans.amount}
- Subtransaction amount is invalid, must be an integer: ${sub.
- Transaction ${id} does not belong to account ${accountId}
- Merging is only possible with 2 transactions, but found ${JS
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/6efc2cc9cbbce127.
Report an issue: GitHub.