{"record":{"id":"8339aa19d840997f","repo":"vxcontrol/pentagi","slug":"authentication-required","errorCode":null,"errorMessage":"Authentication required.","messagePattern":"Authentication required\\.","errorType":"console","errorClass":null,"httpStatus":401,"severity":"error","filePath":"frontend/src/lib/axios.ts","lineNumber":104,"sourceCode":"                    Log.error(\n                        'Failed to parse the return value, please check if the response is returned in JSON format',\n                    );\n                    break;\n                }\n\n                case 400: {\n                    if (err.response?.data) {\n                        Log.warn(err.response.data);\n                        const warns = err.response.data as Record<string, string[]>;\n                        const globalMessage = warns[''] || ['Please confirm your input.'];\n                        error.message = globalMessage[0] as string;\n                    }\n\n                    break;\n                }\n\n                case 401: {\n                    Log.warn('Authentication required.');\n                    localStorage.removeItem(AUTH_STORAGE_KEY);\n\n                    const currentPath = window.location.pathname;\n\n                    if (currentPath !== routes.login()) {\n                        window.location.href = routes.login(currentPath);\n                    }\n\n                    break;\n                }\n\n                case 403: {\n                    const responseData = err.response?.data as undefined | { code?: string };\n\n                    if (\n                        responseData?.code === 'AuthRequired' ||\n                        responseData?.code === 'NotPermitted' ||\n                        responseData?.code === 'PrivilegesRequired' ||","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/frontend/src/lib/axios.ts#L86-L122","documentation":"The axios response interceptor (frontend/src/lib/axios.ts:104) treats HTTP 401 as 'the session is no longer valid'. It logs 'Authentication required.', removes the persisted auth data (localStorage AUTH_STORAGE_KEY), and hard-redirects the browser to the login page, preserving the current path so the user can return after re-authenticating.","triggerScenarios":"Any API call answered with status 401: expired/revoked session cookie, expired JWT/API token, calling the API before login, or the backend rejecting a missing/invalid Authorization header or session cookie.","commonSituations":"User leaves a tab open until the session cookie/JWT expires and then the app performs an action; backend restarted with rotated signing keys invalidating existing tokens; user deleted their API token in settings while other tabs still use it; clock skew causing premature JWT expiry.","solutions":["Re-authenticate: the interceptor already redirects to routes.login(currentPath); log in again and you will be returned to the original page.","Verify the client is actually sending credentials (axios `withCredentials: true` for cookie-based auth) and the backend session cookie is present and not expired.","If 401 appears immediately after login, check backend/auth service clocks and token lifetime configuration.","For in-flight auth refresh, add a refresh-token flow or a request-retry interceptor instead of relying on the hard redirect."],"exampleFix":"// before (default instance, cookies may not be sent cross-origin)\nconst api = axios.create({ baseURL: API_URL });\n// after\nconst api = axios.create({ baseURL: API_URL, withCredentials: true });","handlingStrategy":"try-catch","validationCode":"const authed = !!localStorage.getItem(AUTH_STORAGE_KEY);\nif (!authed) window.location.href = routes.login(window.location.pathname);","typeGuard":"function isUnauthorized(e: unknown): e is AxiosError {\n  return axios.isAxiosError(e) && e.response?.status === 401;\n}","tryCatchPattern":"try {\n  const { data } = await api.get('/me');\n  return data;\n} catch (err) {\n  if (isUnauthorized(err)) {\n    localStorage.removeItem(AUTH_STORAGE_KEY);\n    window.location.href = routes.login(window.location.pathname);\n  }\n  throw err;\n}","preventionTips":["Implement silent session refresh (refresh token or sliding cookie) before requests fire.","Show a session-expiry countdown/re-login modal instead of only hard-redirecting.","Never cache authenticated pages that keep polling after the session can plausibly expire."],"tags":["auth","http-401","session-expired","axios"],"backgroundTag":"authentication-required-401","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}