mattermost-community/focalboard · error
unable to delete the session
Error message
unable to delete the session
What it means
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.
Source
Thrown at server/app/auth.go:138
AuthService: authService,
Props: map[string]interface{}{},
}
err := a.store.CreateSession(&session)
if err != nil {
return "", errors.Wrap(err, "unable to create session")
}
a.metrics.IncrementLoginCount(1)
// TODO: MFA verification
return session.Token, nil
}
// Logout invalidates the user session.
func (a *App) Logout(sessionID string) error {
err := a.store.DeleteSession(sessionID)
if err != nil {
return errors.Wrap(err, "unable to delete the session")
}
a.metrics.IncrementLogoutCount(1)
return nil
}
// RegisterUser creates a new user if the provided data is valid.
func (a *App) RegisterUser(username, email, password string) error {
var user *model.User
if username != "" {
var err error
user, err = a.store.GetUserByUsername(username)
if err != nil && !model.IsErrNotFound(err) {
return err
}
if user != nil {
return errors.New("The username already exists")View on GitHub (pinned to a84bbb65e3)
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
Example fix
// before
err := app.Logout(sessionID)
if err != nil { log.Fatal(err) }
// after
err := app.Logout(sessionID)
if err != nil {
if model.IsErrNotFound(errors.Cause(err)) {
log.Warn("session already gone; treating logout as success")
} else {
log.Errorf("logout failed: %v", errors.Cause(err))
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Only call Logout with a non-empty session ID you actually hold
if sessionID == "" {
return nil // nothing to invalidate
} Type guard
func isSessionAlreadyGone(err error) bool {
return model.IsErrNotFound(errors.Cause(err))
} Try / catch
if err := app.Logout(sessionID); err != nil {
if model.IsErrNotFound(errors.Cause(err)) {
return nil // idempotent: session already deleted
}
return fmt.Errorf("logout failed: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Client sends stale or already-deleted session ID during double logout; DB unavailable; network partition to the database; storage misconfiguration.
Related errors
- unable to create session
- ErrorId.NotLoggedIn
- card limit value is invalid
- database type is unsupported
- cannot notify block subscribers for block %s: %w
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/eb73396460a4fda9.
Report an issue: GitHub.