siyuan-note/siyuan · error
OAuth callback did not include an authorization code
Error message
OAuth callback did not include an authorization code
What it means
The authorization-code flow requires the redirect to include a code query parameter. The callback handler passes the parsed result to Authorize; if the state matched but no code is present, there is nothing to exchange and the library aborts with this error.
Solutions
- Retry the authorization; transient IdP redirects without a code usually succeed on a second attempt
- Verify the authorization server issues response_type=code redirects correctly (test with another OAuth client)
- Check any local proxy/AV software that may strip query strings from 127.0.0.1 callbacks
- If it persists, inspect the callback URL the IdP produced (browser dev tools network log) and compare with the expected format
Defensive patterns
Strategy: retry
Try / catch
if err := h.Authorize(ctx, true); err != nil {
if strings.Contains(err.Error(), "did not include an authorization code") {
// retry the flow; inspect the IdP redirect if it recurs
}
} Prevention
- Verify the authorization server is standards-compliant (response_type=code redirect includes code)
- Check the browser network log for the exact redirect URL when diagnosing
- Rule out proxies/AV software stripping query parameters
When it happens
Trigger: The browser callback reached the local endpoint with the correct state but an empty/missing code parameter — e.g. the IdP redirected without issuing a code, or the code was stripped in transit.
Common situations: IdP misconfiguration where the redirect is performed without the authorization code; a proxy or middleware dropping query parameters; user landing on a redirect URL variant that omits code (e.g. error path handled only via state).
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- configuration is not initialized
- discover OAuth authorization server
- exchange OAuth authorization code
- mcp oauth authorization required
- OAuth authorization failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/662c77e0960ff2cc.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:392
var callback oauthCallbackResult
timer := time.NewTimer(oauthAuthorizationTimeout)
defer timer.Stop()
select {
case callback = <-flow.Result:
case <-ctx.Done():
return ctx.Err()
case <-timer.C:
return fmt.Errorf("OAuth authorization timed out")
}
if callback.Error != "" {
return fmt.Errorf("OAuth authorization failed: %s", callback.Error)
}
if callback.State != state {
return fmt.Errorf("OAuth state mismatch")
}
if callback.Code == "" {
return fmt.Errorf("OAuth callback did not include an authorization code")
}
exchangeCtx := context.WithValue(ctx, oauth2.HTTPClient, h.client)
token, err := config.Exchange(exchangeCtx, callback.Code,
oauth2.VerifierOption(verifier),
oauth2.SetAuthURLParam("resource", prm.Resource))
if err != nil {
return fmt.Errorf("exchange OAuth authorization code: %w", err)
}
if token.TokenType != "" && !strings.EqualFold(token.TokenType, "Bearer") {
return fmt.Errorf("OAuth token endpoint returned unsupported token type %q", token.TokenType)
}
credential = registrationCredential
credential.TokenAuthMethod = authMethod
credential.AccessToken = token.AccessToken
credential.RefreshToken = token.RefreshToken
credential.TokenType = token.TokenType
credential.Expiry = token.ExpiryView on GitHub (pinned to 9f775e8a12)