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
- Clear the browser cookie for this instance and log in again to mint a session with the current installation's hash
- Make GLOBAL_SALT identical between installations that share a database (or never share the DB)
- Communicate that changing GLOBAL_SALT invalidates all existing sessions/tokens and requires re-login
- 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
- Never share a database between installations configured with different GLOBAL_SALT values
- Clear browser cookies after switching an environment's salt or database
- On salt rotation, force full re-login (sessions are invalidated by design)
- Document that sessions are installation-bound and not portable
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
- cookie claim invalid
- session expired
- user hash mismatch - session invalid for this installation
- user has been deleted
- %w - token invalid for this installation
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/b76a34e0d5f06031.
Report an issue: GitHub.