{"record":{"id":"8813d52f6e57c313","repo":"mem0ai/mem0","slug":"user-not-found-8813d5","errorCode":null,"errorMessage":"User not found.","messagePattern":"User not found\\.","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"server/routers/auth.py","lineNumber":157,"sourceCode":"        access_token=create_access_token(str(user.id), user.role),\n        refresh_token=create_refresh_token(str(user.id), db),\n    )\n\n\n@router.post(\"/refresh\", response_model=TokenResponse)\n@limiter.limit(\"20/minute\")\ndef refresh(request: Request, body: RefreshRequest, db: Session = Depends(get_db)):\n    payload = decode_token(body.refresh_token)\n    if payload.get(\"type\") != \"refresh\":\n        raise HTTPException(status_code=401, detail=\"Invalid token type.\")\n\n    jti = payload.get(\"jti\")\n    if not jti:\n        raise HTTPException(status_code=401, detail=\"Refresh token is no longer valid.\")\n\n    user = db.get(User, payload[\"sub\"])\n    if user is None:\n        raise HTTPException(status_code=401, detail=\"User not found.\")\n\n    consume_refresh_jti(jti, db)\n\n    return TokenResponse(\n        access_token=create_access_token(str(user.id), user.role),\n        refresh_token=create_refresh_token(str(user.id), db),\n    )\n\n\n@router.get(\"/me\", response_model=UserResponse)\ndef me(user: User = Depends(require_auth)):\n    return user\n\n\n@router.patch(\"/me\", response_model=UserResponse)\ndef update_me(\n    body: UpdateProfileRequest,\n    user: User = Depends(require_auth),","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/server/routers/auth.py#L139-L175","documentation":"Raised by POST /auth/refresh when the refresh token is structurally valid and has a jti, but the user id in its `sub` claim no longer matches a row in the database (db.get(User, payload[\"sub\"]) returns None). The token is authentic but refers to a deleted or never-existent account, so the server refuses rotation.","triggerScenarios":"User account was deleted (hard delete) after the refresh token was issued; token references a user id from a different database/environment (e.g. staging token sent to a fresh local DB); `sub` claim altered to a non-existent id while keeping a valid signature is not possible, so this is almost always deletion or environment mismatch.","commonSituations":"DB was reset or re-seeded while clients held refresh tokens; account deletion/GDPR purge leaves live tokens; dev pointing the client at the wrong server instance.","solutions":["Confirm the user id in the token's sub claim exists in the users table of the database this server is connected to","If the DB was reset or the environment changed, discard stored tokens and log in again","If account deletion is expected, make sure the client handles 401 here by clearing session state and redirecting to login"],"exampleFix":"// before: keep retrying refresh with a token whose user no longer exists\nwhile (true) { try { await refresh(); break; } catch (e) { /* retry */ } }\n\n// after: treat 401 \"User not found.\" as terminal — clear tokens and re-login\ncatch (e) {\n  if (e.status === 401) { clearStoredTokens(); router.push(\"/login\"); }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e.status === 401 && e.detail === \"User not found.\") {\n    clearStoredTokens();\n    redirectToLogin(); // account gone; refresh can never succeed\n  }\n  throw e;\n}","preventionTips":["Handle 401 on /auth/refresh as a forced logout, never as a retryable error","Run a single database across environments that share tokens; never mix staging and production tokens","When deleting users server-side, also revoke/blacklist their outstanding refresh tokens"],"tags":["auth","refresh-token","user-deleted","http-401"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}