router-for-me/CLIProxyAPI · error
OAuth error: %s
Error message
OAuth error: %s
What it means
The Claude OAuth callback received an error query parameter — the authorization server refused the request and redirected back with ?error=... (per OAuth2 RFC 6749 §4.1.2.1). The handler logs it, sends OAuthResult{Error: errorParam} to the waiting flow, and returns HTTP 400 with body "OAuth error: <errorParam>".
Source
Thrown at internal/auth/claude/oauth_server.go:190
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Extract parameters
query := r.URL.Query()
code := query.Get("code")
state := query.Get("state")
errorParam := query.Get("error")
// Validate required parameters
if errorParam != "" {
log.Errorf("OAuth error received: %s", errorParam)
result := &OAuthResult{
Error: errorParam,
}
s.sendResult(result)
http.Error(w, fmt.Sprintf("OAuth error: %s", errorParam), http.StatusBadRequest)
return
}
if code == "" {
log.Error("No authorization code received")
result := &OAuthResult{
Error: "no_code",
}
s.sendResult(result)
http.Error(w, "No authorization code received", http.StatusBadRequest)
return
}
if state == "" {
log.Error("No state parameter received")
result := &OAuthResult{
Error: "no_state",
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Read the error value: access_denied means the user declined — re-run login and approve; invalid_scope means trim/fix requested scopes; invalid_client means fix the client registration
- Re-run the login flow (the handler has already delivered the error to the waiting goroutine, which surfaces it to the CLI)
- Check the provider's app console for the client's status and redirect URI configuration
Defensive patterns
Strategy: fallback
Validate before calling
// nothing to pre-validate on the caller side; the error originates upstream.
// After the flow: inspect the returned OAuthResult
result, err := server.WaitForCode(ctx)
if err == nil && result.Error != "" { switch result.Error {
case "access_denied": /* user declined; prompt and retry login */
case "invalid_scope": /* request fewer scopes, retry */
default: /* surface result.Error to the user */
} } Type guard
func oauthFailed(r *OAuthResult) bool { return r != nil && r.Error != "" } Try / catch
result, err := server.WaitForCode(ctx)
if err != nil { return fmt.Errorf("oauth wait: %w", err) }
if result.Error != "" { return fmt.Errorf("oauth provider error: %s", result.Error) } Prevention
- Pre-verify client_id/redirect_uri/scopes in the provider console
- Educate users that cancelling consent surfaces access_denied
- Handle result.Error explicitly in every login wrapper
When it happens
Trigger: Browser lands on /callback?error=access_denied (user clicked deny), ?error=invalid_client, ?error=invalid_scope, or any provider-specific error code instead of a code parameter.
Common situations: User cancels the consent screen; requested scopes not granted to the CLI client; client_id misregistered; the provider revoked or expired the app's access during device authorization.
Related errors
- callback_timeout
- Method not allowed
- No authorization code received
- OAuth error: %s
- request failed with status %d: %s
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/69cc59faa744e9ef.
Report an issue: GitHub.