Kuberwastaken/claurst · error · anyhow::Error

Failed to parse redirect URI

Error message

Failed to parse redirect URI '{}': {}

What it means

url::Url::parse rejected the OAuth redirect_uri configured for the MCP server's OAuth flow (e.g. missing scheme, malformed host, or invalid characters). The URI is used to bind the local callback listener; if it cannot be parsed, no callback can be received.

Solutions

  1. Print the redirect URI from the error message and fix its syntax (must include scheme, e.g. http://127.0.0.1:PORT/callback)
  2. Use the redirect_uri exactly as registered with the OAuth provider, including scheme and port
  3. Trim whitespace/quotes when reading the URI from config or environment
  4. Construct the URI programmatically (e.g. format!("http://127.0.0.1:{}/callback", port)) instead of hand-typing it

Example fix

// before
let redirect_uri = "127.0.0.1:8080/callback";
// after
let redirect_uri = "http://127.0.0.1:8080/callback";
Defensive patterns

Strategy: validation

Validate before calling

fn validate_redirect(uri: &str) -> Result<(), String> {
    let u = url::Url::parse(uri).map_err(|e| e.to_string())?;
    if u.scheme() != "http" && u.scheme() != "https" { return Err("scheme must be http(s)".into()); }
    Ok(())
}

Prevention

When it happens

Trigger: Passing a malformed redirect_uri to run_mcp_auth_session / bind_callback_listener — e.g. a value without a scheme ('127.0.0.1:8080/callback'), containing spaces or illegal characters, or an empty string read from config.

Common situations: Typo in a settings.json redirect URI; hand-built URI missing 'http://'; copying a URI with trailing whitespace or quotes from docs; shell variable interpolation producing an empty value.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/08ebf11f60e136a7. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/mcp/src/oauth.rs:218

        &metadata.authorization_endpoint,
        &redirect_uri,
        &verifier,
    );

    Ok(McpAuthSession {
        server_name: server_name.to_string(),
        auth_url,
        redirect_uri,
        verifier,
        metadata,
    })
}

async fn bind_callback_listener(
    redirect_uri: &str,
) -> anyhow::Result<(TcpListener, String, String)> {
    let redirect_url = url::Url::parse(redirect_uri)
        .map_err(|e| anyhow::anyhow!("Failed to parse redirect URI '{}': {}", redirect_uri, e))?;
    let host = redirect_url
        .host_str()
        .ok_or_else(|| anyhow::anyhow!("Redirect URI '{}' is missing host", redirect_uri))?
        .to_string();
    let port = redirect_url
        .port_or_known_default()
        .ok_or_else(|| anyhow::anyhow!("Redirect URI '{}' is missing port", redirect_uri))?;
    let callback_path = if redirect_url.path().is_empty() {
        "/callback".to_string()
    } else {
        redirect_url.path().to_string()
    };
    let listener = TcpListener::bind((host.as_str(), port))
        .await
        .map_err(|e| anyhow::anyhow!("Failed to bind OAuth callback listener on {}:{}: {}", host, port, e))?;

    Ok((listener, host, callback_path))
}

View on GitHub (pinned to b0637c97ec)