{"record":{"id":"eb73396460a4fda9","repo":"mattermost-community/focalboard","slug":"unable-to-delete-the-session","errorCode":null,"errorMessage":"unable to delete the session","messagePattern":"unable to delete the session","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/app/auth.go","lineNumber":138,"sourceCode":"\t\tAuthService: authService,\n\t\tProps:       map[string]interface{}{},\n\t}\n\terr := a.store.CreateSession(&session)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"unable to create session\")\n\t}\n\n\ta.metrics.IncrementLoginCount(1)\n\n\t// TODO: MFA verification\n\treturn session.Token, nil\n}\n\n// Logout invalidates the user session.\nfunc (a *App) Logout(sessionID string) error {\n\terr := a.store.DeleteSession(sessionID)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"unable to delete the session\")\n\t}\n\n\ta.metrics.IncrementLogoutCount(1)\n\n\treturn nil\n}\n\n// RegisterUser creates a new user if the provided data is valid.\nfunc (a *App) RegisterUser(username, email, password string) error {\n\tvar user *model.User\n\tif username != \"\" {\n\t\tvar err error\n\t\tuser, err = a.store.GetUserByUsername(username)\n\t\tif err != nil && !model.IsErrNotFound(err) {\n\t\t\treturn err\n\t\t}\n\t\tif user != nil {\n\t\t\treturn errors.New(\"The username already exists\")","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/mattermost-community/focalboard/blob/a84bbb65e32edf972856b329417096ac413518e9/server/app/auth.go#L120-L156","documentation":"Logout wraps an error from store.DeleteSession as 'unable to delete the session'. It means the server tried to invalidate the session identified by sessionID but the storage delete operation failed. The session may remain valid, so the caller should not assume the user is logged out.","triggerScenarios":"App.Logout(sessionID) called with a sessionID whose delete fails in the store: DB write error, empty/invalid sessionID hitting a constraint, or store outage.","commonSituations":"Client sends stale or already-deleted session ID during double logout; DB unavailable; network partition to the database; storage misconfiguration.","solutions":["Check the wrapped cause to distinguish not-found vs real DB error","If the session was already deleted, treat the logout as idempotent and ignore not-found errors","Verify DB connectivity and the sessions table health","Implement client-side token removal so the user is logged out locally even if server delete fails"],"exampleFix":"// before\nerr := app.Logout(sessionID)\nif err != nil { log.Fatal(err) }\n// after\nerr := app.Logout(sessionID)\nif err != nil {\n    if model.IsErrNotFound(errors.Cause(err)) {\n        log.Warn(\"session already gone; treating logout as success\")\n    } else {\n        log.Errorf(\"logout failed: %v\", errors.Cause(err))\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Only call Logout with a non-empty session ID you actually hold\nif sessionID == \"\" {\n    return nil // nothing to invalidate\n}","typeGuard":"func isSessionAlreadyGone(err error) bool {\n    return model.IsErrNotFound(errors.Cause(err))\n}","tryCatchPattern":"if err := app.Logout(sessionID); err != nil {\n    if model.IsErrNotFound(errors.Cause(err)) {\n        return nil // idempotent: session already deleted\n    }\n    return fmt.Errorf(\"logout failed: %w\", err)\n}","preventionTips":["Treat logout as idempotent on the client: clear the token regardless of server result","Avoid double-logout with stale session IDs","Validate sessionID is non-empty before calling","Monitor DeleteSession failures for store outages"],"tags":["session","logout","database"],"backgroundTag":"session-deletion-failure","analyzedSha":"a84bbb65e32edf972856b329417096ac413518e9","analyzedAt":"2026-08-30T09:22:20.720Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}