{"record":{"id":"af930d34afe7387f","repo":"actualbudget/actual","slug":"account-with-id-accountid-not-found","errorCode":null,"errorMessage":"Account with ID ${accountId} not found.","messagePattern":"Account with ID (.+?) not found\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/accounts/Account.tsx","lineNumber":1089,"sourceCode":"    await reconciliation.lockTransactions(accountId);\n    await this.refetchTransactions();\n  };\n\n  onReconcile = async (amount: number | null) => {\n    this.setState(({ showCleared }) => ({\n      reconcileAmount: amount,\n      showCleared: true,\n      prevShowCleared: showCleared,\n    }));\n  };\n\n  onDoneReconciling = async () => {\n    const { accountId } = this.props;\n    const account = this.props.accounts.find(\n      account => account.id === accountId,\n    );\n    if (!account) {\n      throw new Error(`Account with ID ${accountId} not found.`);\n    }\n\n    const { reconcileAmount } = this.state;\n\n    await reconciliation.finishReconciliation(account.id, reconcileAmount, () =>\n      this.lockTransactions(),\n    );\n\n    const lastReconciled = new Date().getTime().toString();\n    this.props.onUpdateAccount({ ...account, last_reconciled: lastReconciled });\n\n    this.setState(state => ({\n      reconcileAmount: null,\n      showCleared: state.prevShowCleared,\n    }));\n  };\n\n  onCreateReconciliationTransaction = async (diff: number) => {","sourceCodeStart":1071,"sourceCodeEnd":1107,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/accounts/Account.tsx#L1071-L1107","documentation":"onDoneReconciling in AccountInternal resolves the account from the `accounts` prop by accountId and throws if it's missing, before finishing reconciliation. Like the rename path, it treats a desync between accountId and the accounts list as an unrecoverable invariant violation.","triggerScenarios":"Clicking 'Done reconciling' after the account was deleted (another tab/device/sync removal) or before the accounts list has loaded; accountId from the route no longer present in the prop.","commonSituations":"Multi-tab usage where one tab deletes the account mid-reconciliation; sync removing the account while the reconciler modal is open; slow initial load letting a user finish reconciliation first.","solutions":["Disable the reconciliation UI until the account resolves from the accounts list (guard render on account existence).","Re-read the account from the persistent store by id rather than the prop so it survives list filtering.","Handle the missing case gracefully: close the reconciliation modal, show a notice, and navigate away from the deleted account."],"exampleFix":"// before\nconst account = this.props.accounts.find(a => a.id === accountId);\nif (!account) throw new Error(`Account with ID ${accountId} not found.`);\n\n// after\nconst account = this.props.accounts.find(a => a.id === accountId);\nif (!account) {\n  // account disappeared mid-reconciliation; abort quietly\n  this.props.navigate('/accounts');\n  return;\n}","handlingStrategy":"validation","validationCode":"const account = accounts.find(a => a.id === accountId);\nif (!account) {\n  navigate('/accounts'); // abort reconciliation for a vanished account\n  return;\n}","typeGuard":"function accountExists(accounts: AccountEntity[], accountId: string | undefined): accounts is AccountEntity[] & { length: number } {\n  return accountId != null && accounts.some(a => a.id === accountId);\n}","tryCatchPattern":"try {\n  await onDoneReconciling();\n} catch (e) {\n  if (String(e.message).includes('not found')) {\n    closeModal();\n    notify('Account was deleted before reconciliation could finish.');\n  } else throw e;\n}","preventionTips":["Gate the reconciliation modal on the account being present in the accounts list.","Close reconciliation state when the account is deleted (subscribe to store updates).","Avoid long-lived modal flows across tabs that may delete the underlying account."],"tags":["react","race-condition","stale-data","reconciliation"],"backgroundTag":"entity-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}