actualbudget/actual · error · Error
Account with ID ${upgradingId} not found.
Error message
Account with ID ${upgradingId} not found. What it means
When linking a GoCardless (Nordigen) bank account to upgrade an existing (off-budget/manual) account, Actual looks up the account row by the provided upgradingId. This error is thrown when no accounts row exists for that id, meaning the client referenced an account that no longer exists in the budget database.
Source
Thrown at packages/loot-core/src/server/accounts/app.ts:190
upgradingId,
offBudget = false,
startingDate,
startingBalance,
}: LinkAccountBaseParams & {
requisitionId: string;
account: SyncServerGoCardlessAccount;
}) {
let id;
const bank = await link.findOrCreateBank(account.institution, requisitionId);
if (upgradingId) {
const accRow = await db.first<db.DbAccount>(
'SELECT * FROM accounts WHERE id = ?',
[upgradingId],
);
if (!accRow) {
throw new Error(`Account with ID ${upgradingId} not found.`);
}
id = accRow.id;
await db.update('accounts', {
id,
account_id: account.account_id,
bank: bank.id,
account_sync_source: 'goCardless',
});
} else {
id = uuidv4();
await db.insertWithUUID('accounts', {
id,
account_id: account.account_id,
mask: account.mask,
name: account.name,
official_name: account.official_name,
bank: bank.id,View on GitHub (pinned to d4334cb6e6)
Solutions
- Refresh the account list and re-run the bank-link flow, selecting the account again so a fresh id is sent.
- Verify the id exists: run a query 'SELECT * FROM accounts WHERE id = ?' with the id before linking.
- Re-sync the budget on the affected device so local state matches the server, then retry.
- If the account was deleted intentionally, create a new manual account and link the bank account to that instead.
Example fix
// before
await send('gocardless-link-account', {
upgradingId: staleAccountId,
...rest,
});
// after
const acc = await q('SELECT id FROM accounts WHERE id = ?', [staleAccountId]);
if (!acc) {
console.warn('Account no longer exists; linking as a new account instead');
}
await send('gocardless-link-account', { upgradingId: acc ? staleAccountId : null, ...rest }); Defensive patterns
Strategy: validation
Validate before calling
const acc = await db.first('SELECT id FROM accounts WHERE id = ?', [upgradingId]);
if (!acc) {
throw new Error(`Refusing to link: account ${upgradingId} does not exist`);
} Type guard
async function accountExists(id: string): Promise<boolean> {
return !!(await db.first('SELECT id FROM accounts WHERE id = ?', [id]));
} Try / catch
try {
await send('gocardless-link-account', { upgradingId, ...rest });
} catch (e) {
if (/Account with ID .* not found/.test(e.message)) {
await refreshAccounts(); // re-run flow with fresh ids
} else throw e;
} Prevention
- Always re-fetch account ids from the current budget state before bank-link operations.
- Avoid caching account ids across budget switches or reloads.
- Sync devices before performing bank-link upgrades.
When it happens
Trigger: Calling the 'gocardless-link-account' (linkGoCardlessAccount) handler with an upgradingId that was deleted, belongs to a different budget file, or was never persisted (stale client state).
Common situations: The user deleted the manual account in another tab/device before finishing the link flow; a stale sync left the UI showing a nonexistent account; the client sent an id from a different budget.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- `payeeName` is required when adding a transaction
- Invalid Origin header
- Invalid GoCardless identifier: ${String(id)}
- Requisition not linked yet
- Provided account id is not linked to given requisition
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/a8b756d52bec5304.
Report an issue: GitHub.