actualbudget/actual · error
Transaction not found: ${id}
Error message
Transaction not found: ${id} What it means
moveTransaction() first fetches the transaction by id to validate it exists and belongs to the given account; if db.getTransaction(id) returns nothing it throws Error(`Transaction not found: ${id}`). This guards the sort-order recalculation from operating on a missing row.
Source
Thrown at packages/loot-core/src/server/transactions/app.ts:81
async function deleteTransaction(transaction: Pick<TransactionEntity, 'id'>) {
await handleBatchUpdateTransactions({ deleted: [transaction] });
return {};
}
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({View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-fetch the transaction list and verify the id exists before moving
- Refresh/sync so local data is current if the transaction was just created elsewhere
- Handle the not-found case in the caller (skip or re-select a valid transaction)
Example fix
// before
await moveTransaction({ id, accountId, targetId }); // Error: Transaction not found
// after
const tx = await getTransaction(id);
if (!tx) throw new Error(`Transaction not found: ${id}`);
await moveTransaction({ id, accountId, targetId }); Defensive patterns
Strategy: validation
Validate before calling
const tx = await getTransaction(id);
if (!tx) {
throw new Error(`Cannot move: transaction ${id} not found`);
}
if (tx.account !== accountId) {
throw new Error('Transaction belongs to a different account');
} Type guard
function isTransactionNotFound(e: unknown, id: string): boolean {
return e instanceof Error && e.message === `Transaction not found: ${id}`;
} Try / catch
try {
await moveTransaction({ id, accountId, targetId });
} catch (e) {
if (isTransactionNotFound(e, id)) {
await refreshTransactionList();
} else throw e;
} Prevention
- Validate ids against a fresh transaction fetch before moving
- Sync before acting on transactions created on other devices
- Validate account ownership before invoking moves
- Guard automation scripts against stale id lists
When it happens
Trigger: moveTransaction({ id, accountId, targetId }) is called with an id that doesn't exist (deleted transaction, stale list, wrong id string).
Common situations: UI keeping a reference to a transaction deleted on another device; plugin/API automation using ids from an old export; id typos in scripts.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Transaction not found: ${id}
- Account with ID ${accountId} does not exist.
- `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.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/a02f8d1bed76f951.
Report an issue: GitHub.