{"record":{"id":"5bafddab1bac0829","repo":"AlistGo/alist","slug":"failed-to-load-roles-w","errorCode":null,"errorMessage":"failed to load roles: %w","messagePattern":"failed to load roles: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"server/mcp/auth.go","lineNumber":95,"sourceCode":"\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\n\t}\n\treturn nil\n}\n\n// resolveUser extracts the authenticated user from context.\nfunc resolveUser(ctx context.Context) (*model.User, error) {\n\tuser, ok := ctx.Value(userKey).(*model.User)\n\tif !ok || user == nil {\n\t\treturn nil, fmt.Errorf(\"authentication required\")\n\t}\n\treturn user, nil\n}\n\n// buildFsContext resolves path and sets meta in context for fs operations.\nfunc buildFsContext(ctx context.Context, user *model.User, path string) (context.Context, string, error) {\n\treqPath, err := user.JoinPath(path)","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/mcp/auth.go#L77-L113","documentation":"Returned by loadRoles (server/mcp/auth.go:95) when the authenticated user has roles (len(user.Role) > 0) but op.GetRolesByUserID(user.ID) fails. Authentication succeeded; enriching the user with role details hit a database error, and the wrapped %w carries the underlying cause.","triggerScenarios":"Database fails or times out exactly between the user lookup and the roles query; the role-mapping table is missing or corrupted by a partial migration; connection pool exhaustion under load.","commonSituations":"Migrations that created the users table but not the role-mapping table; transient DB drops during deploys; concurrent MCP bursts exhausting connections.","solutions":["Check the wrapped error in server logs for the real DB cause","Verify migrations for the roles tables completed","If transient (timeout, pool exhaustion), retry after the DB recovers","Cap MCP client concurrency if connection exhaustion is reproducible"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to load roles\") { backoff.Retry(call, 3) }","preventionTips":["Verify role-table migrations before enabling MCP","Cap MCP concurrency to protect the connection pool","Alert on the wrapped DB error"],"tags":["mcp","auth","database","roles"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}