{"record":{"id":"6c3959ea343c0b02","repo":"actualbudget/actual","slug":"internal-error-account-with-id-targetaccountid","errorCode":null,"errorMessage":"Internal error: account with ID ${targetAccountId} not found.","messagePattern":"Internal error: account with ID (.+?) not found\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/mobile/accounts/AccountsPage.tsx","lineNumber":492,"sourceCode":"          />\n        );\n      },\n      onReorder: e => {\n        const [key] = e.keys;\n        const accountIdToMove = key as AccountEntity['id'];\n        const targetAccountId = e.target.key as AccountEntity['id'];\n\n        if (e.target.dropPosition === 'before') {\n          moveAccount.mutate({\n            id: accountIdToMove,\n            targetId: targetAccountId,\n          });\n        } else if (e.target.dropPosition === 'after') {\n          const targetAccountIndex = accounts.findIndex(\n            account => account.id === e.target.key,\n          );\n          if (targetAccountIndex === -1) {\n            throw new Error(\n              `Internal error: account with ID ${targetAccountId} not found.`,\n            );\n          }\n\n          const nextToTargetAccount = accounts[targetAccountIndex + 1];\n\n          moveAccount.mutate({\n            id: accountIdToMove,\n            // Due to the way `moveAccount` works, we use the account next to the\n            // actual target account here because `moveAccount` always shoves the\n            // account *before* the target account.\n            // On the other hand, using `null` as `targetId`moves the account\n            // to the end of the list.\n            targetId: nextToTargetAccount?.id || null,\n          });\n        }\n      },\n    });","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/mobile/accounts/AccountsPage.tsx#L474-L510","documentation":"AccountsPage's mobile drag-and-drop account reordering throws this when a drop target ('after' position) account ID cannot be found in the local `accounts` array. It signals a state desync between the drag payload and the rendered account list. Note the throw interpolates `targetAccountId`, which is not the variable computed in this region (`targetAccountIndex`), so the message may print `undefined` — itself a bug worth fixing while handling the error.","triggerScenarios":"Drag-reordering an account with dropPosition === 'after' where `accounts.findIndex(account => account.id === e.target.key)` returns -1: the drop target key is stale or not present in the accounts list at the moment the reorder event fires.","commonSituations":"Stale accounts state during a concurrent sync (account deleted on another device mid-drag), a dropped item whose target key belongs to a different list section, or a component re-render that replaced `accounts` between drag start and drop.","solutions":["Refresh the accounts list (reload from the store/server) and retry the drag operation.","Fix the throw to interpolate the actual target key (`e.target.key`) instead of the undefined `targetAccountId` so the message is debuggable.","Gracefully return instead of throwing when the index is -1, since a stale drop target is a UI-level condition, not a fatal internal error.","Check for concurrent account deletion (sync removing the target account) in your app state."],"exampleFix":"// before\nthrow new Error(\n  `Internal error: account with ID ${targetAccountId} not found.`,\n);\n// after\nconst targetAccountId = e.target.key;\nif (targetAccountIndex === -1) {\n  throw new Error(\n    `Internal error: account with ID ${targetAccountId} not found.`,\n  );\n}","handlingStrategy":"validation","validationCode":"const targetAccountIndex = accounts.findIndex(a => a.id === e.target.key);\nif (e.target.dropPosition === 'after' && targetAccountIndex === -1) {\n  return; // stale drop target; skip instead of throwing\n}","typeGuard":"function accountExists(accounts: { id: string }[], id: string): boolean {\n  return accounts.some(a => a.id === id);\n}","tryCatchPattern":"try {\n  await onReorder(e);\n} catch (err) {\n  if (String(err).includes('not found')) {\n    await refreshAccounts(); // resync and recover\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always re-validate drop target IDs against the current list before mutating order.","Refresh account state before starting long-lived drag interactions.","Interpolate the actual key variable in error messages to keep them debuggable.","Treat missed lookups as no-ops for UI reorder events."],"tags":["ui","drag-and-drop","state-desync","internal-error"],"backgroundTag":"stale-drop-target-id","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}