{"record":{"id":"456da44ccfb9b9d9","repo":"vxcontrol/pentagi","slug":"session-expired","errorCode":null,"errorMessage":"session expired","messagePattern":"session expired","errorType":"http","errorClass":null,"httpStatus":401,"severity":"warning","filePath":"backend/pkg/server/auth/auth_middleware.go","lineNumber":111,"sourceCode":"// non-malicious session/token invalidation rather than a genuine application\n// error, so callers can log it at a quieter level.\nfunc isRoutineAuthFailure(authErr error) bool {\n\treturn errors.Is(authErr, errCookieClaimInvalid) ||\n\t\terrors.Is(authErr, errSessionExpired) ||\n\t\terrors.Is(authErr, errUserHashMismatch)\n}\n\n// errCookieClaimInvalid is returned by tryUserCookieAuthentication when the\n// session cookie is present but missing one or more required claims (expired\n// or otherwise invalid session) - a routine, expected condition.\n//\n// errSessionExpired and errUserHashMismatch mark the same category of routine\n// session/token invalidation, just detected a bit later during validation: a\n// session past its TTL, or a stored hash that no longer matches the user\n// record (e.g. after a password change or a test database reseed).\nvar (\n\terrCookieClaimInvalid = errors.New(\"cookie claim invalid\")\n\terrSessionExpired     = errors.New(\"session expired\")\n\terrUserHashMismatch   = errors.New(\"user hash mismatch\")\n)\n\nfunc (p *AuthMiddleware) tryUserCookieAuthentication(c *gin.Context) (authResult, error) {\n\tsessionObject, exists := c.Get(sessions.DefaultKey)\n\tif !exists {\n\t\treturn authResultSkip, errors.New(\"can't find session object\")\n\t}\n\n\tsession, ok := sessionObject.(sessions.Session)\n\tif !ok {\n\t\treturn authResultFail, errors.New(\"not a session object\")\n\t}\n\n\tuid := session.Get(\"uid\")\n\tuhash := session.Get(\"uhash\")\n\trid := session.Get(\"rid\")\n\tprm := session.Get(\"prm\")","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/auth/auth_middleware.go#L93-L129","documentation":"errSessionExpired indicates the session referenced by the cookie exists but is past its TTL. Like the other sentinel errors here it is a routine invalidation: the middleware fails the request (usually 401) instead of erroring, and the user simply needs to authenticate again.","triggerScenarios":"Any request made after the session's MaxAge/TTL elapsed — leaving the tab open overnight, returning after the session lifetime configured in the sessions middleware, or a session persisted beyond its expiry window.","commonSituations":"Long-running browser sessions or websockets that never refresh the cookie; short session TTL configured for security while users expect longer lifetimes; clock skew between issuing and validating nodes.","solutions":["Log in again to create a fresh session","Increase the session TTL/MaxAge configuration if users are logged out too aggressively","Implement token/cookie refresh (sliding expiration) or re-authenticate automatically when a 401 with this cause is received"],"exampleFix":"// before\n// every request fails after TTL with no recovery\n// after\nclient.interceptors.response.use(null, async (err) => {\n  if (err.response?.status === 401 && !err.config._retried) {\n    await refreshSession();\n    err.config._retried = true;\n    return client(err.config);\n  }\n  throw err;\n});","handlingStrategy":"retry","validationCode":"const sessionIssuedAt = Number(localStorage.getItem('sessionIssuedAt') ?? 0);\nconst expired = Date.now() - sessionIssuedAt > SESSION_TTL_MS;","typeGuard":null,"tryCatchPattern":"client.interceptors.response.use(null, async (err) => {\n  if (err.response?.status === 401 && !err.config._retried) {\n    await reauthenticate();\n    err.config._retried = true;\n    return client(err.config);\n  }\n  throw err;\n});","preventionTips":["Configure a session TTL appropriate to real user workflows","Implement sliding expiration / periodic re-auth in long-lived SPA sessions","Treat any 401 as re-authentication signal, never retry blindly without re-login"],"tags":["authentication","session","expiry"],"backgroundTag":"jwt-token-expired","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}