siyuan-note/siyuan · error
load GitHub user failed: %w
Error message
load GitHub user failed: %w
What it means
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.
Source
Thrown at kernel/model/oidc_provider/provider.go:162
},
RedirectURL: redirectURL,
Scopes: scopes,
},
}
}
func isDefaultOIDCScopes(scopes []string) bool {
if len(scopes) != 3 {
return false
}
return contains(scopes, oidc.ScopeOpenID) && contains(scopes, "profile") && contains(scopes, "email")
}
func exchangeGitHubClaims(ctx context.Context, token *oauth2.Token) (map[string]any, error) {
client := oauth2.NewClient(ctx, oauth2.StaticTokenSource(token))
user := map[string]any{}
if err := getGitHubJSON(ctx, client, "https://api.github.com/user", &user); err != nil {
return nil, fmt.Errorf("load GitHub user failed: %w", err)
}
delete(user, "email")
if id, ok := user["id"]; ok {
user["sub"] = fmt.Sprint(id)
}
emails := []struct {
Email string `json:"email"`
Primary bool `json:"primary"`
Verified bool `json:"verified"`
}{}
if err := getGitHubJSON(ctx, client, "https://api.github.com/user/emails", &emails); err == nil {
all := make([]string, 0, len(emails))
for _, email := range emails {
if !email.Verified {
continue
}
all = append(all, email.Email)
if email.Primary {View on GitHub (pinned to 8641553a1f)
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
Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get("https://api.github.com/rate_limit")
if err != nil {
return errors.New("api.github.com unreachable from this host")
}
resp.Body.Close() Try / catch
user, err := provider.Exchange(ctx, code, verifier, nonce)
if err != nil && strings.Contains(err.Error(), "load GitHub user failed") {
// transient GitHub/network issue: allow one bounded retry of the whole flow
return retryLoginFlow(maxAttempts=2)
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- generate image failed: %w
- get liandi article info failed [sc=%d]
- send article to liandi failed [sc=%d]
- GitHub OAuth client secret is required
- exchange OIDC authorization code failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/9e7a7b7e97a04b29.
Report an issue: GitHub.