actualbudget/actual · error
Transaction ${id} does not belong to account ${accountId}
Error message
Transaction ${id} does not belong to account ${accountId} What it means
moveTransaction also verifies the transaction's account field matches the accountId argument; a mismatch throws 'Transaction <id> does not belong to account <accountId>'. This prevents moving a transaction between positions of an account it does not belong to.
Source
Thrown at packages/loot-core/src/server/db/index.ts:927
*
* @param id - The ID of the transaction to move
* @param accountId - The account the transaction belongs to
* @param targetId - The ID of the transaction to place AFTER, or null to place at top
*/
export async function moveTransaction(
id: string,
accountId: string,
targetId: string | null,
) {
await batchMessages(async () => {
const transaction = await getTransaction(id);
if (!transaction) {
throw new Error(`Transaction not found: ${id}`);
}
// Validate that the transaction belongs to the specified account
if (transaction.account !== accountId) {
throw new Error(
`Transaction ${id} does not belong to account ${accountId}`,
);
}
// Convert date string (YYYY-MM-DD) to integer format (YYYYMMDD) for SQL query
const dateInt = parseInt(transaction.date.replace(/-/g, ''), 10);
// Get transactions to reorder against.
// If this is a child transaction, scope to siblings with the same parent_id.
// Otherwise, get all parent transactions for the same date (excluding children).
// Query in DESC order to match UI display order.
const isChild = transaction.is_child && transaction.parent_id;
const transactions = await all<{ id: string; sort_order: number }>(
isChild
? `SELECT vt.id, vt.sort_order
FROM v_transactions vt
WHERE vt.parent_id = ?
ORDER BY sort_order DESC, id`View on GitHub (pinned to d4334cb6e6)
Solutions
- Pass the account id the transaction currently belongs to (transaction.account), not the destination account
- Re-fetch the transaction to get its current account before calling moveTransaction
- If the goal is to change the transaction's account, update the transaction's account field instead of using moveTransaction
- Catch the error, re-sync, and retry with the corrected accountId
Example fix
// before await aqlQuery.moveTransaction(txn.id, targetAccountId, targetId); // after await aqlQuery.moveTransaction(txn.id, txn.account, targetId);
Defensive patterns
Strategy: validation
Validate before calling
const txn = await aqlQuery.getTransaction(txnId);
if (txn && txn.account !== accountId) {
throw new Error(`Transaction ${txnId} belongs to ${txn.account}, not ${accountId}`);
} Type guard
function belongsToAccount(txn: { account: string } | null, accountId: string): txn is { account: string } {
return txn !== null && txn.account === accountId;
} Try / catch
try {
await aqlQuery.moveTransaction(txnId, accountId, targetId);
} catch (e) {
if (e.message.includes('does not belong to account')) {
const txn = await aqlQuery.getTransaction(txnId);
await aqlQuery.moveTransaction(txnId, txn.account, targetId);
} else throw e;
} Prevention
- Always pass the transaction's current account (txn.account), not the destination
- Re-fetch the transaction before moving in case an account transfer changed ownership
- In drag-and-drop UIs, bind the source account, not the drop target
- For account changes, update the transaction record instead of using moveTransaction
When it happens
Trigger: Calling moveTransaction with an accountId different from transaction.account — e.g. passing the target account instead of the source account, or moving within account B a transaction that lives in account A.
Common situations: UI drag-and-drop sending the wrong account context; off-by-one after a transaction was transferred between accounts (its account field changed); batch operations iterating accounts with mismatched id variables.
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.
- Account mismatch: transaction belongs to account ${transacti
- 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/f48bbee5554aafcc.
Report an issue: GitHub.