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

  1. Check for transient network issues on loopback and retry the authentication flow
  2. 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)