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

  1. Check the wrapped cause to distinguish not-found vs real DB error
  2. If the session was already deleted, treat the logout as idempotent and ignore not-found errors
  3. Verify DB connectivity and the sessions table health
  4. 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

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


AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30). Data as JSON: /api/errors/eb73396460a4fda9. Report an issue: GitHub.