{"record":{"id":"86d32f67d3b7bec2","repo":"makeplane/plane","slug":"authentication-unsuccessful","errorCode":null,"errorMessage":"Authentication unsuccessful","messagePattern":"Authentication unsuccessful","errorType":"exception","errorClass":"AppError","httpStatus":null,"severity":"critical","filePath":"apps/live/src/lib/auth.ts","lineNumber":95,"sourceCode":"  try {\n    const userService = new UserService();\n    const user = await userService.currentUser(cookie);\n    if (user.id !== userId) {\n      throw new AppError(\"Authentication unsuccessful: User ID mismatch\", { code: \"AUTH_USER_MISMATCH\" });\n    }\n\n    return {\n      user: {\n        id: user.id,\n        name: user.display_name,\n      },\n    };\n  } catch (error) {\n    const appError = new AppError(error, {\n      context: { operation: \"handleAuthentication\" },\n    });\n    logger.error(\"Authentication failed\", appError);\n    throw new AppError(\"Authentication unsuccessful\", { code: appError.code });\n  }\n};\n","sourceCodeStart":77,"sourceCodeEnd":98,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/live/src/lib/auth.ts#L77-L98","documentation":"The catch-all re-throw at the bottom of handleAuthentication. Any error inside the auth flow that is not the explicit user-mismatch (including a thrown AUTH_USER_MISMATCH that gets re-wrapped here) is normalized to the generic message 'Authentication unsuccessful' with the original code preserved via `appError.code`. This is the error a live-connection client sees whenever authentication fails for any reason other than missing credentials.","triggerScenarios":" userService.currentUser(cookie) rejects (network error, 401/403 from the API, expired cookie, backend 5xx); or the explicit AUTH_USER_MISMATCH thrown at line 81 is caught here and re-thrown as the generic message. Also fires if AppError construction itself receives a non-Error / undefined and `appError.code` resolves to undefined.","commonSituations":"Cookie expired or was cleared server-side (session revoked) while the websocket tab stayed open; the API host is unreachable from the live service (network/DNS/CORS between live pod and api pod); the user's account was deactivated mid-session; mis-configuration of the live service's API base URL so currentUser() 404s.","solutions":["Read the server logs: `logger.error(\"Authentication failed\", appError)` on line 94 logs the underlying error with its context — the generic client message hides it, the log does not.","If the code is AUTH_USER_MISMATCH, follow error [0]; if it is undefined/empty, the underlying error was a non-AppError (likely a network or HTTP error from currentUser).","Confirm the cookie is still valid by making a REST `/users/me/` call from the same browser; if that 401s, the session is dead — re-authenticate.","Verify connectivity between the live service and the API (API_BASE_URL, internal service DNS, proxy headers forwarded)."],"exampleFix":"// before: the catch loses the real cause for the client\nthrow new AppError(\"Authentication unsuccessful\", { code: appError.code });\n// after: preserve the cause so callers/UI can branch on it\nthrow new AppError(\"Authentication unsuccessful\", { code: appError.code, cause: appError });","handlingStrategy":"try-catch","validationCode":"// Verify the cookie still resolves to a user before opening the live socket\nconst ok = await fetch('/api/users/me/', { credentials: 'include' });\nif (!ok.ok) { await reauthenticate(); }","typeGuard":null,"tryCatchPattern":"try { await connectLiveDocument(); }\ncatch (e) {\n  // The generic message hides the cause; check server logs for the real error.\n  if (e instanceof AppError && (e.code === 'AUTH_USER_MISMATCH' || !e.code)) {\n    await reauthenticate();\n  } else { notifyTransientError(e); }\n}","preventionTips":["Treat any live auth failure as 'session is dead' and force re-authentication.","Server-side: preserve the cause in AppError so clients can branch on it.","Log the underlying error with request id for correlation with the generic client message."],"tags":["auth","websocket","live","catch-all","error-masking"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}