Kuberwastaken/claurst · error · anyhow::Error
Failed to write OAuth callback response
Error message
Failed to write OAuth callback response: {} What it means
Writing the plain-text 'authentication finished' HTTP response back to the browser's callback socket failed. The authorization code was already captured from the request line; this failure means the user-visible success page could not be delivered, e.g. the peer closed the connection early.
Solutions
- Check for transient network issues on loopback and retry the authentication flow
- Inspect the callback socket lifecycle; a browser closing the tab immediately after redirect can abort the write
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at src-rust/crates/mcp/src/oauth.rs:275 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/e65f0087d20b6290.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/oauth.rs:275
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())
.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");
}
}View on GitHub (pinned to b0637c97ec)