{"record":{"id":"735f5f346511ddeb","repo":"actualbudget/actual","slug":"user-not-found","errorCode":null,"errorMessage":"User not found","messagePattern":"User not found","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"packages/sync-server/src/app-account.js","lineNumber":193,"sourceCode":"\n  const { prefs } = req.body || {};\n\n  if (!prefs || typeof prefs !== 'object') {\n    res.status(400).send({ status: 'error', reason: 'invalid-prefs' });\n    return;\n  }\n\n  setServerPrefs(prefs);\n\n  res.send({ status: 'ok', data: {} });\n});\n\napp.get('/validate', (req, res) => {\n  const session = validateSession(req, res);\n  if (session) {\n    const user = getUserInfo(session.user_id);\n    if (!user) {\n      res.status(400).send({ status: 'error', reason: 'User not found' });\n      return;\n    }\n\n    res.send({\n      status: 'ok',\n      data: {\n        validated: true,\n        userName: user?.user_name,\n        permission: user?.role,\n        userId: session?.user_id,\n        displayName: user?.display_name,\n        loginMethod: session?.auth_method,\n        prefs: getServerPrefs(),\n      },\n    });\n  }\n});\n","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-account.js#L175-L211","documentation":"HTTP 400 from GET /validate with `reason:'User not found'`. The session token was cryptographically valid, but `getUserInfo(session.user_id)` returned no row — i.e. the user behind the token was deleted from the account database after the token was issued. The endpoint refuses to validate a session whose backing user no longer exists.","triggerScenarios":"GET /validate with a token whose user_id was deleted (DELETE /users or direct DB removal) between login and validation; stale tokens persisted by a client across a server user wipe.","commonSituations":"Admin deletes users while their clients are still running; restoring an old account.sqlite backup that lacks recently created users; DB re-creation during server re-bootstrap while clients keep cached tokens.","solutions":["Log in again to obtain a fresh token for an existing user.","Check the users list (admin GET /users) to confirm the user still exists; re-create the user if it was deleted unintentionally.","Clear the client's cached token when users are removed server-side so it doesn't keep validating a dead session."],"exampleFix":"// before: blindly reusing a stored token\nconst res = await api.get('/validate', { headers: { 'X-ACTUAL-TOKEN': storedToken } });\n// after: re-login when validation reports a missing user\nif (res.data?.reason === 'User not found') {\n  const { token } = await login(username, password);\n  storedToken = token;\n}","handlingStrategy":"fallback","validationCode":"// a token can only be validated server-side, but you can detect the stale-user case from the response\nif (validateRes.data?.reason === 'User not found') invalidateStoredToken();","typeGuard":"function isUserMissing(res) {\n  return res?.status === 'error' && res.reason === 'User not found';\n}","tryCatchPattern":"try {\n  const res = await get('/validate', { headers: authHeaders(token) });\n  if (res.data.data.validated) return res.data.data;\n  throw new SessionError(res.data.reason);\n} catch (e) {\n  if (isUserMissing(e.response?.data)) {\n    clearToken();\n    return startLoginFlow(); // fallback: re-login\n  }\n  throw e;\n}","preventionTips":["Clear cached tokens whenever the admin deletes or recreates users","Treat 'User not found' on /validate as an automatic re-login trigger","Avoid restoring account.sqlite backups without notifying connected clients"],"tags":["authentication","session","stale-token","http-400"],"backgroundTag":"stale-session-token","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}