Kuberwastaken/claurst · error
OAuth callback path mismatch: expected
Error message
OAuth callback path mismatch: expected '{}', got '{}' What it means
During OAuth authorization-code flow, the library spins up a local callback server and waits for the identity provider to redirect to it. After writing the response page, it validates that the incoming request path equals the expected callback path; a mismatch means the request did not come from the expected redirect and is rejected.
Solutions
- Retry the auth flow and complete the browser login without editing the URL
- Ensure the redirect_uri registered with the OAuth provider matches the local callback path exactly
- Check that no other process is bound to the same callback port and sending requests
- Re-run the auth session so a fresh callback path/port is bound
Defensive patterns
Strategy: try-catch
Try / catch
match run_mcp_auth_session(server).await {
Err(e) if e.to_string().contains("callback path mismatch") => {
// restart flow; warn user not to touch the callback URL and check the port is free
}
other => other?,
} Prevention
- Complete the browser OAuth step promptly and do not modify the redirect URL
- Ensure the redirect_uri registered with the provider matches the local callback path
- Avoid letting other tools bind the same local callback port
When it happens
Trigger: wait_for_authorization_code (invoked by run_mcp_auth_session) receives an HTTP request on the local callback port whose path differs from the registered callback_path.
Common situations: User or another app visited the callback URL directly; a port previously used by another tool now receives stray requests; the OAuth client's registered redirect URI path was changed server-side; browser extension or health-check probe hits the local server.
Related errors
- OAuth state mismatch — possible CSRF attack
- OAuth state mismatch — possible CSRF attack
- Missing code or state in OAuth callback
- No query string in callback
- Callback server dropped
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/268376765e2f8535.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/oauth.rs:278
.await
.map_err(|e| anyhow::anyhow!("Failed to read OAuth callback headers: {}", e))?;
if header.trim().is_empty() {
break;
}
}
let path = request_line.split_whitespace().nth(1).unwrap_or("");
let parsed_url = url::Url::parse(&format!("http://{}{}", host, path))
.map_err(|e| anyhow::anyhow!("Failed to parse OAuth callback URL '{}': {}", path, e))?;
let response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\nMCP OAuth authentication finished. You can close this tab.\r\n";
writer
.write_all(response.as_bytes())
.await
.map_err(|e| anyhow::anyhow!("Failed to write OAuth callback response: {}", e))?;
if parsed_url.path() != callback_path {
anyhow::bail!(
"OAuth callback path mismatch: expected '{}', got '{}'",
callback_path,
parsed_url.path()
);
}
if let Some(expected_state) = expected_state {
let received_state = parsed_url
.query_pairs()
.find(|(key, _)| key == "state")
.map(|(_, value)| value.to_string());
if received_state.as_deref() != Some(expected_state) {
anyhow::bail!("OAuth state mismatch — possible CSRF attack");
}
}
parsed_url
.query_pairs()View on GitHub (pinned to b0637c97ec)