Kuberwastaken/claurst · warning · anyhow::Error
Failed to read OAuth callback request
Error message
Failed to read OAuth callback request: {} What it means
After accepting the browser's callback connection, reading the HTTP request line from the socket failed at the I/O level (connection reset, timeout, or broken socket before a full line arrived). The browser connected but the request could not be read.
Solutions
- Retry the auth flow — a single aborted probe connection shouldn't prevent the real browser request
- Register an http:// (not https://) redirect URI with the OAuth provider so the browser speaks plain HTTP
- Exclude the callback port from port-scanning security agents
- Check proxies/middleware that might reset loopback connections
Example fix
// before "redirect_uris": ["https://127.0.0.1:8090/callback"] // after "redirect_uris": ["http://127.0.0.1:8090/callback"]
Defensive patterns
Strategy: retry
Try / catch
match run_mcp_auth_flow(server).await {
Err(e) if e.to_string().contains("read OAuth callback request") => {
eprintln!("callback read interrupted; retrying");
run_mcp_auth_flow(server).await
}
other => other,
} Prevention
- Register http:// (not https://) redirect URIs with the provider for local callbacks
- Bind only to 127.0.0.1 to minimize stray connections
- Exclude the callback port from port-scanning security tools
When it happens
Trigger: wait_for_authorization_code reading the request line when the client disconnects abruptly, a port scanner or health probe opens and immediately closes the connection, or TLS is attempted against the plain-HTTP listener.
Common situations: Antivirus/security software probing the open port; browser preconnect connections torn down; an https:// redirect URI registered with the provider while the listener is plain http.
Related errors
- API key creation failed
- Bridge register: server returned
- exchange_code: HTTP
- Failed to read OAuth callback headers
- refresh: HTTP
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/89fb6edcbafa3b9a.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/oauth.rs:255
async fn wait_for_authorization_code(
listener: TcpListener,
host: &str,
callback_path: &str,
expected_state: Option<&str>,
) -> anyhow::Result<String> {
let (mut socket, _) = tokio::time::timeout(Duration::from_secs(180), listener.accept())
.await
.map_err(|_| anyhow::anyhow!("Timeout waiting for OAuth callback"))?
.map_err(|e| anyhow::anyhow!("Failed to accept OAuth callback connection: {}", e))?;
let (reader, mut writer) = socket.split();
let mut reader = BufReader::new(reader);
let mut request_line = String::new();
reader
.read_line(&mut request_line)
.await
.map_err(|e| anyhow::anyhow!("Failed to read OAuth callback request: {}", e))?;
loop {
let mut header = String::new();
reader
.read_line(&mut header)
.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())View on GitHub (pinned to b0637c97ec)