vxcontrol/pentagi · error · errUserHashMismatch

%w - session invalid for this installation

Error message

%w - session invalid for this installation

What it means

tryUserCookieAuthentication compares the hash stored in the session (sessionHash) with the current hash in the database (dbHash). On mismatch it returns errUserHashMismatch wrapped as "session invalid for this installation". The user hash binds sessions to a specific installation/salt, so a session issued elsewhere or before a salt change is rejected.

Source

Thrown at backend/pkg/server/auth/auth_middleware.go:175

	dbHash, userStatus, err := p.userCache.GetUserHash(userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return authResultFail, errors.New("user has been deleted")
		}
		return authResultFail, fmt.Errorf("error checking user status: %w", err)
	}

	switch userStatus {
	case models.UserStatusBlocked:
		return authResultFail, errors.New("user has been blocked")
	case models.UserStatusCreated:
		return authResultFail, errors.New("user is not ready")
	case models.UserStatusActive:
	}

	if dbHash != sessionHash {
		return authResultFail, fmt.Errorf("%w - session invalid for this installation", errUserHashMismatch)
	}

	c.Set("prm", prms)
	c.Set("uid", userID)
	c.Set("uhash", sessionHash)
	c.Set("rid", rid.(uint64))
	c.Set("exp", exp.(int64))
	c.Set("gtm", gtm.(int64))
	c.Set("tid", tid.(string))
	c.Set("uname", uname.(string))

	if slices.Contains(prms, PrivilegeAutomation) {
		c.Set("cpt", "automation")
	}

	return authResultOk, nil
}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Clear the browser cookie for this instance and log in again to mint a session with the current installation's hash
  2. Make GLOBAL_SALT identical between installations that share a database (or never share the DB)
  3. Communicate that changing GLOBAL_SALT invalidates all existing sessions/tokens and requires re-login
  4. Ensure load balancer routes users to replicas configured with the same salt

Example fix

// before
// dev instance sharing prod DB with different salt
GLOBAL_SALT=dev-salt
// after
GLOBAL_SALT=<same-as-issuing-installation>
Defensive patterns

Strategy: fallback

Try / catch

if errors.Is(err, auth.ErrUserHashMismatch) {
    // session belongs to another installation: drop it and re-authenticate
    clearSessionCookie()
    return redirectToLogin()
}

Prevention

When it happens

Trigger: Cookie issued by a different PentAGI installation (different GLOBAL_SALT) pointed at the same DB; user row's hash regenerated (salt change, password/user rebuild) while the browser still holds the old cookie; copying a production DB into a dev instance with a different salt and reusing browser cookies.

Common situations: Staging/prod sharing one database with different salts; restoring a DB dump locally then loading an old cookie; changing GLOBAL_SALT env without forcing users to re-login.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/b76a34e0d5f06031. Report an issue: GitHub.