{"record":{"id":"a3e69756a630c856","repo":"github/github-mcp-server","slug":"failed-to-query-viewer-login-w","errorCode":null,"errorMessage":"failed to query viewer login: %w","messagePattern":"failed to query viewer login: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/lockdown/lockdown.go","lineNumber":156,"sourceCode":"\treturn viewerLogin == strings.ToLower(username), nil\n}\n\nfunc (c *RepoAccessCache) viewerLoginFor(ctx context.Context) (string, error) {\n\tc.viewerMu.Lock()\n\tdefer c.viewerMu.Unlock()\n\tif c.viewerLogin != \"\" {\n\t\treturn c.viewerLogin, nil\n\t}\n\tif c.client == nil {\n\t\treturn \"\", fmt.Errorf(\"nil GraphQL client\")\n\t}\n\tvar query struct {\n\t\tViewer struct {\n\t\t\tLogin githubv4.String\n\t\t}\n\t}\n\tif err := c.client.Query(ctx, &query, nil); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to query viewer login: %w\", err)\n\t}\n\tlogin := strings.ToLower(string(query.Viewer.Login))\n\tif login == \"\" {\n\t\treturn \"\", fmt.Errorf(\"viewer login returned empty\")\n\t}\n\tc.viewerLogin = login\n\treturn c.viewerLogin, nil\n}\n\n// setViewerLogin seeds the cached viewer login from a piggy-backed query response.\nfunc (c *RepoAccessCache) setViewerLogin(login string) {\n\tif login == \"\" {\n\t\treturn\n\t}\n\tc.viewerMu.Lock()\n\tdefer c.viewerMu.Unlock()\n\tif c.viewerLogin == \"\" {\n\t\tc.viewerLogin = strings.ToLower(login)","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/lockdown/lockdown.go#L138-L174","documentation":"The lockdown RepoAccessCache lazily runs the GraphQL query `viewer { login }` with the request's token the first time a lockdown safety check needs the viewer identity (getViewerLogin via viewerLoginFor). Any failure of that query - transport, authentication, rate limiting, wrong endpoint - is wrapped with this message. Note the cache memoizes the login, so the query runs once per cache instance, not per tool call.","triggerScenarios":"First lockdown check (IsSafeContent) on a request whose token cannot complete the Viewer query: expired/revoked PAT (401), GITHUB_HOST pointing at the wrong or unreachable endpoint, DNS/proxy failure, or a secondary rate limit (403).","commonSituations":"Long-lived deployments with rotating tokens that silently expire; GHES hosts configured without a scheme or with an untrusted self-signed cert; egress firewalls blocking the API host.","solutions":["Classify the wrapped error first: 401/403 means token problem, timeout/DNS means network problem","Test the token directly: curl -H \"Authorization: Bearer $TOKEN\" https://api.github.com/user","Verify GITHUB_HOST is a full https:// origin reachable from the server process","If rate-limited, back off and let the next request repopulate the cache"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// preflight: prove the token can read its own user before enabling lockdown\nreq, _ := http.NewRequest(http.MethodGet, apiBase+\"/user\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+token)\nresp, err := http.DefaultClient.Do(req)\nif err != nil || resp.StatusCode != http.StatusOK {\n\treturn errors.New(\"token cannot query viewer; lockdown login lookups will fail\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := cache.IsSafeContent(ctx, user, owner, repo); err != nil {\n\tif strings.Contains(err.Error(), \"failed to query viewer login\") {\n\t\t// unwrap: 401/403 -> fix the token (no retry); timeout/DNS -> retry with backoff\n\t}\n}","preventionTips":["Alert on 401-wrapped viewer-login failures so expired tokens are caught early","Prefer user-scoped tokens for lockdown deployments","Keep GITHUB_HOST a full https origin and monitor its reachability"],"tags":["go","graphql","lockdown","authentication","network"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}