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

  1. Re-fetch the transaction list and verify the id exists before moving
  2. Refresh/sync so local data is current if the transaction was just created elsewhere
  3. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/a02f8d1bed76f951. Report an issue: GitHub.