{"record":{"id":"5bf24fcb04bf78d7","repo":"AlistGo/alist","slug":"password-has-been-changed","errorCode":null,"errorMessage":"password has been changed","messagePattern":"password has been changed","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"server/mcp/auth.go","lineNumber":79,"sourceCode":"\t\tif err := loadRoles(guest); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn guest, nil\n\t}\n\n\t// JWT token\n\tclaims, err := common.ParseToken(token)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid token: %w\", err)\n\t}\n\n\tuser, err := op.GetUserByName(claims.Username)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"user not found: %w\", err)\n\t}\n\n\tif claims.PwdTS != user.PwdTS {\n\t\treturn nil, fmt.Errorf(\"password has been changed\")\n\t}\n\tif user.Disabled {\n\t\treturn nil, fmt.Errorf(\"user is disabled\")\n\t}\n\n\tif err := loadRoles(user); err != nil {\n\t\treturn nil, err\n\t}\n\treturn user, nil\n}\n\nfunc loadRoles(user *model.User) error {\n\tif len(user.Role) > 0 {\n\t\troles, err := op.GetRolesByUserID(user.ID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load roles: %w\", err)\n\t\t}\n\t\tuser.RolesDetail = roles","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/mcp/auth.go#L61-L97","documentation":"Returned by authenticateToken (server/mcp/auth.go:79) when the JWT's PwdTS claim does not equal the current user.PwdTS — the password was changed (or the account's password timestamp was bumped) after this token was issued. It is a deliberate invalidation of all pre-change tokens, not corruption.","triggerScenarios":"User changed their password in the web UI, then an MCP client reuses the old token; admin reset a password, invalidating every token that user had issued.","commonSituations":"Automation tokens breaking after routine password rotation; shared accounts whose password is changed by one team while another team's tooling still holds the old token.","solutions":["Log in again after any password change and update the stored MCP token","Treat this specific message as 're-authenticate', not 'retry'","For service accounts, avoid password rotation or automate token refresh after rotation"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"password has been changed\") { token = login(user, newPassword); retryOnce() }","preventionTips":["Refresh stored tokens immediately after password changes","Use dedicated service accounts to decouple MCP tokens from human password rotation"],"tags":["mcp","auth","token-invalidation","password"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}