actualbudget/actual · error

Account with ID ${this.props.accountId} not found.

Error message

Account with ID ${this.props.accountId} not found.

What it means

AccountInternal's renameAccountName handler looks up the account in the `accounts` prop by `accountId` and throws when no match exists. The component assumes its accounts list is always in sync with the accountId prop; when the list is stale/empty or the id is invalid, the rename cannot proceed and it fails fast.

Source

Thrown at packages/desktop-client/src/components/accounts/Account.tsx:801

  onAddTransaction = () => {
    this.setState({ isAdding: true });
  };

  onSaveName = (name: string) => {
    const accountNameError = validateAccountName(
      name,
      this.props.accountId ?? '',
      this.props.accounts,
    );
    if (accountNameError) {
      this.setState({ nameError: accountNameError });
    } else {
      const account = this.props.accounts.find(
        account => account.id === this.props.accountId,
      );
      if (!account) {
        throw new Error(`Account with ID ${this.props.accountId} not found.`);
      }
      this.props.onUpdateAccount({ ...account, name });
      this.setState({ nameError: '' });
    }
  };

  onToggleExtraBalances = () => {
    this.props.setShowExtraBalances(!this.props.showExtraBalances);
  };

  onMenuSelect = async (
    item:
      | 'link'
      | 'unlink'
      | 'close'
      | 'reopen'
      | 'export'
      | 'remove-sorting'

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Ensure the accounts list is loaded before rendering the editable name field (gate on accounts.length / loading state).
  2. Look the account up from the server store by id (e.g. via the entity/query layer) instead of only the `accounts` prop, so closed/filtered accounts still resolve.
  3. Return a validation error ('Account not found') to the UI instead of throwing, and clear the stale id by redirecting to the accounts page.

Example fix

// before
const account = this.props.accounts.find(a => a.id === this.props.accountId);
if (!account) throw new Error(`Account with ID ${this.props.accountId} not found.`);

// after
const account = this.props.accounts.find(a => a.id === this.props.accountId);
if (!account) {
  this.setState({ nameError: 'Account not found' });
  return;
}
Defensive patterns

Strategy: validation

Validate before calling

const account = accounts.find(a => a.id === accountId);
if (!account) {
  // account missing/stale — abort rename instead of throwing
  return;
}

Type guard

function isKnownAccount(accounts: AccountEntity[], accountId: string): boolean {
  return accounts.some(a => a.id === accountId);
}

Try / catch

try {
  await renameAccount(accountId, newName);
} catch (e) {
  if (String(e.message).includes('not found')) {
    setError('This account no longer exists.');
  } else throw e;
}

Prevention

When it happens

Trigger: Renaming an account (submitting the rename form) while the `accounts` prop no longer contains the account: the account was deleted in another view/tab, the list hasn't loaded yet, or accountId points to a closed/off-balance account filtered out of `accounts`.

Common situations: Deleting an account from a second browser tab then renaming it in the first; race where the account list query is still loading; navigating to a stale deep-link /accounts/<deleted-id> and editing the name.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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