{"record":{"id":"b77c5636d7439ff1","repo":"ruvnet/ruflo","slug":"user-not-found","errorCode":null,"errorMessage":"User not found","messagePattern":"User not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/server/auth.ts","lineNumber":467,"sourceCode":"\t\t\ttoken: result.oauth?.token?.value,\n\t\t\tsessionId,\n\t\t\tsecretSessionId,\n\t\t\tisAdmin: result.user?.isAdmin || adminTokenManager.isAdmin(sessionId),\n\t\t};\n\t}\n\n\tif (isApi) {\n\t\tconst authorization = headers.get(\"Authorization\");\n\t\tif (authorization?.startsWith(\"Bearer \")) {\n\t\t\tconst token = authorization.slice(7);\n\t\t\tconst hash = await sha256(token);\n\t\t\tsessionId = secretSessionId = hash;\n\n\t\t\tconst cacheHit = await collections.tokenCaches.findOne({ tokenHash: hash });\n\t\t\tif (cacheHit) {\n\t\t\t\tconst user = await collections.users.findOne({ hfUserId: cacheHit.userId });\n\t\t\t\tif (!user) {\n\t\t\t\t\tthrow new Error(\"User not found\");\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tuser,\n\t\t\t\t\tsessionId,\n\t\t\t\t\ttoken,\n\t\t\t\t\tsecretSessionId,\n\t\t\t\t\tisAdmin: user.isAdmin || adminTokenManager.isAdmin(sessionId),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst response = await fetch(\"https://huggingface.co/api/whoami-v2\", {\n\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\"Unauthorized\");\n\t\t\t}\n","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/ruflo/src/ruvocal/src/lib/server/auth.ts#L449-L485","documentation":"Thrown in the API-token auth path when a token-hash cache hit is found (tokenCaches collection) but the referenced user no longer exists in the users collection (lookup by hfUserId: cacheHit.userId). It indicates a stale cache entry pointing at a deleted/missing user account.","triggerScenarios":"A client sends a Bearer token whose hash is cached, but the user record behind cacheHit.userId was deleted from the users collection after the cache was written. Reached only when isApi is true and the Authorization: Bearer header's token hash matches a tokenCaches document.","commonSituations":"User account was deleted (GDPR/retention) but tokenCaches was not cleaned up; a DB restore/migration dropped users but kept tokenCaches; multi-instance setup where the cache and users collections diverged; test fixture inserted a tokenCache with a fabricated userId.","solutions":["Delete the stale tokenCaches entry (by tokenHash) so the next auth call falls through to the HF whoami path and re-creates or properly rejects it.","Add a cleanup that removes tokenCaches rows when a user is deleted.","Investigate why users and tokenCaches diverged (audit deletion code paths).","Re-authenticate with the token so the cache is repopulated correctly after the user is restored."],"exampleFix":"// before — user gone but cache hit remains → throw\n\n// after — on 'User not found' from a cache hit, evict and retry once\ntry { await auth(headers); }\ncatch (e) {\n  if (e.message === 'User not found') {\n    await collections.tokenCaches.deleteOne({ tokenHash: hash });\n    // surface a clean 401 so the client re-authenticates\n  }\n  throw e;\n}","handlingStrategy":"fallback","validationCode":"// pre-flight: confirm the cached user still exists before trusting the cache\nconst cacheHit = await collections.tokenCaches.findOne({ tokenHash: hash });\nif (cacheHit) {\n  const user = await collections.users.findOne({ hfUserId: cacheHit.userId });\n  if (!user) { await collections.tokenCaches.deleteOne({ tokenHash: hash }); /* fall through to whoami */ }\n}","typeGuard":"async function cacheRefersToExistingUser(cacheHit: { userId: string }): Promise<boolean> { return !!(await collections.users.findOne({ hfUserId: cacheHit.userId })); }","tryCatchPattern":"try { return await authApi(headers); } catch (e) { if ((e as Error).message === 'User not found') { await collections.tokenCaches.deleteOne({ tokenHash: await sha256(token) }); } throw e; }","preventionTips":["Delete tokenCaches rows when a user is deleted.","Treat a cache-vs-users mismatch as an eviction, then re-authenticate.","Audit deletion code paths so users and tokenCaches stay consistent."],"tags":["auth","cache","database","ruvocal"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}