{"record":{"id":"9e7a7b7e97a04b29","repo":"siyuan-note/siyuan","slug":"load-github-user-failed-w","errorCode":null,"errorMessage":"load GitHub user failed: %w","messagePattern":"load GitHub user failed: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/oidc_provider/provider.go","lineNumber":162,"sourceCode":"\t\t\t},\n\t\t\tRedirectURL: redirectURL,\n\t\t\tScopes:      scopes,\n\t\t},\n\t}\n}\n\nfunc isDefaultOIDCScopes(scopes []string) bool {\n\tif len(scopes) != 3 {\n\t\treturn false\n\t}\n\treturn contains(scopes, oidc.ScopeOpenID) && contains(scopes, \"profile\") && contains(scopes, \"email\")\n}\n\nfunc exchangeGitHubClaims(ctx context.Context, token *oauth2.Token) (map[string]any, error) {\n\tclient := oauth2.NewClient(ctx, oauth2.StaticTokenSource(token))\n\tuser := map[string]any{}\n\tif err := getGitHubJSON(ctx, client, \"https://api.github.com/user\", &user); err != nil {\n\t\treturn nil, fmt.Errorf(\"load GitHub user failed: %w\", err)\n\t}\n\tdelete(user, \"email\")\n\tif id, ok := user[\"id\"]; ok {\n\t\tuser[\"sub\"] = fmt.Sprint(id)\n\t}\n\temails := []struct {\n\t\tEmail    string `json:\"email\"`\n\t\tPrimary  bool   `json:\"primary\"`\n\t\tVerified bool   `json:\"verified\"`\n\t}{}\n\tif err := getGitHubJSON(ctx, client, \"https://api.github.com/user/emails\", &emails); err == nil {\n\t\tall := make([]string, 0, len(emails))\n\t\tfor _, email := range emails {\n\t\t\tif !email.Verified {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tall = append(all, email.Email)\n\t\t\tif email.Primary {","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/oidc_provider/provider.go#L144-L180","documentation":"For GitHub providers, Exchange() calls exchangeGitHubClaims, which uses the exchanged OAuth token to call GET https://api.github.com/user. Any failure of that HTTP call (transport error, non-2xx status from getGitHubJSON, decode error) is wrapped with this message, so login succeeds at the token step but fails when loading the user profile.","triggerScenarios":"Provider.Exchange with kind=github where the api.github.com/user request fails: network outage, proxy blocking api.github.com, token lacking read:user scope (403/404), token revoked mid-flow, or GitHub rate limiting (403 with rate-limit headers).","commonSituations":"Corporate proxy/firewall blocking api.github.com; GitHub OAuth app scopes customized to drop read:user; hitting GitHub's per-IP rate limit on shared egress (CI, NAT); transient GitHub incidents.","solutions":["Confirm the kernel host can reach https://api.github.com/user (curl it; check proxy settings)","Ensure the OAuth app scopes include read:user and user:email, or reset scopes to the defaults in SiYuan's GitHub OIDC configuration","Check rate-limit status (X-RateLimit-Remaining) and retry after the reset window if the status was 403 with rate-limit headers","Retry the login; if GitHub is having an incident, wait and try again","Regenerate the flow if the access token was revoked between exchange and profile load"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"resp, err := http.Get(\"https://api.github.com/rate_limit\")\nif err != nil {\n    return errors.New(\"api.github.com unreachable from this host\")\n}\nresp.Body.Close()","typeGuard":null,"tryCatchPattern":"user, err := provider.Exchange(ctx, code, verifier, nonce)\nif err != nil && strings.Contains(err.Error(), \"load GitHub user failed\") {\n    // transient GitHub/network issue: allow one bounded retry of the whole flow\n    return retryLoginFlow(maxAttempts=2)\n}","preventionTips":["Whitelist api.github.com in corporate proxies/firewalls","Keep default scopes read:user and user:email","Monitor GitHub rate-limit headers on shared egress IPs","Subscribe to GitHub status for incident awareness"],"tags":["github","api","network","oauth2"],"backgroundTag":"upstream-api-error","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}