siyuan-note/siyuan · warning
OAuth callback was already handled
Error message
OAuth callback was already handled
What it means
After passing validation, CompleteMCPOAuth delivers the callback result to the flow's buffered Result channel in a non-blocking select. If no reader is waiting and the channel is full/already delivered, the callback was already handled — the waiting goroutine that consumes the result already finished (or the flow completed). This error prevents double delivery.
Solutions
- Ignore this error if the OAuth flow actually succeeded — it typically indicates a benign duplicate callback.
- Ensure the callback endpoint is called once per flow; deduplicate on the client/proxy side.
- Check for browser prefetch or extensions reissuing the redirect and disable them for the callback.
- If it appears without a successful login, restart the authorization flow.
- Verify no custom automation double-posts the callback.
Defensive patterns
Strategy: try-catch
Try / catch
if err := CompleteMCPOAuth(flowID, code, state, callbackErr, issuer); err != nil {
if strings.Contains(err.Error(), "already handled") {
log.Info("duplicate OAuth callback ignored") // benign; flow already finished
}
} Prevention
- Treat duplicate callbacks as benign when login already succeeded
- Disable prefetch/aggressive extensions for the callback URL
- Deduplicate callback requests at the proxy or handler level
- Do not re-post callbacks in automation scripts
When it happens
Trigger: CompleteMCPOAuth invoked a second time for the same logical callback after the Result channel was already consumed: duplicate HTTP callback requests (browser retry/prefetch), the user reloading the callback URL, or two callback routes firing for one flow.
Common situations: Browser resends the redirect request; user refreshes the callback page; a proxy retries the request; monitoring/crawler hits the callback URL with the same parameters after completion.
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/c953f19a62d22df3.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/mcp/client/oauth.go:608
delete(oauthFlows.items, flowID)
oauthFlows.Unlock()
return fmt.Errorf("OAuth flow is missing or expired")
}
if state != flow.State {
oauthFlows.Unlock()
return fmt.Errorf("OAuth state mismatch")
}
if issuer != "" && issuer != flow.Issuer {
oauthFlows.Unlock()
return fmt.Errorf("OAuth issuer mismatch")
}
delete(oauthFlows.items, flowID)
oauthFlows.Unlock()
select {
case flow.Result <- oauthCallbackResult{Code: code, State: state, Error: callbackError}:
return nil
default:
return fmt.Errorf("OAuth callback was already handled")
}
}
func IsLoopbackCallback(remoteAddr string) bool {
host, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return false
}
ip := net.ParseIP(host)
return ip != nil && ip.IsLoopback()
}
func refreshOAuthCredential(ctx context.Context, client *http.Client, credential oauthCredential) (oauthCredential, bool, error) {
values := url.Values{
"grant_type": {"refresh_token"},
"refresh_token": {credential.RefreshToken},
"resource": {credential.Resource},
}View on GitHub (pinned to 9f775e8a12)