Hmbown/CodeWhale · critical

Failed to build HTTP client

Error message

Failed to build HTTP client

What it means

Panic from `.expect("Failed to build HTTP client")` on `reqwest::ClientBuilder::build()` in `VisionTools::new_with_route_client` (crates/tui/src/vision/tools.rs:39). The builder applies a 120s timeout and the crate TLS settings (`crate::tls::reqwest_client_builder`); `build()` fails only when reqwest cannot initialize its underlying connector/TLS backend, which is treated as a hard startup error for vision tooling.

Solutions

  1. Ensure the TLS crypto provider is installed at startup: call the crate's `install_crypto_provider()` equivalent before constructing vision tools.
  2. Check Cargo feature flags for reqwest/rustls consistency between the TUI crate and the embedding binary.
  3. Reproduce in a minimal binary calling `crate::tls::reqwest_client_builder().build()` and inspect the returned io/error to identify the backend issue.
  4. If a caller cannot tolerate a panic, switch to a fallible constructor returning Result and surface the message instead of expect.

Example fix

// before
let client = crate::tls::reqwest_client_builder().timeout(Duration::from_secs(120)).build().expect("Failed to build HTTP client");
// after
install_crypto_provider();
let client = crate::tls::reqwest_client_builder().timeout(Duration::from_secs(120)).build().expect("Failed to build HTTP client (TLS backend init failed)");
Defensive patterns

Strategy: validation

Validate before calling

// at process startup, before any reqwest client is built
install_crypto_provider(); // installs rustls ring/aws-lc provider where needed

Try / catch

let client = crate::tls::reqwest_client_builder()
    .timeout(Duration::from_secs(120))
    .build()
    .with_context("Failed to build HTTP client")?; // or expect with context at call sites that cannot fail gracefully

Prevention

When it happens

Trigger: Calling `new_with_route_client` in a binary that links an incompatible or disabled TLS backend (rustls with no crypto provider installed, or a broken native-tls/openssl), or in environments where reqwest's resolver/socket initialization fails (e.g. blocked system resolver on exotic targets).

Common situations: Statically linked or musl builds missing TLS crypto init; running before `install_crypto_provider()` is called for rustls (see `install_crypto_provider` used in app-server tests); embedding the TUI crate in another binary with a different reqwest feature set.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b52d2d7c35eb76e3. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/vision/tools.rs:39

    route_client: Option<CodewhaleClient>,
}

impl ImageAnalyzeTool {
    #[cfg(test)]
    #[must_use]
    pub fn new(config: VisionModelConfig) -> Self {
        Self::new_with_route_client(config, None)
    }

    #[must_use]
    pub fn new_with_route_client(
        config: VisionModelConfig,
        route_client: Option<CodewhaleClient>,
    ) -> Self {
        let client = crate::tls::reqwest_client_builder()
            .timeout(Duration::from_secs(120))
            .build()
            .expect("Failed to build HTTP client");
        Self {
            config,
            client,
            route_client,
        }
    }

    async fn read_image_file(path: &Path) -> Result<(String, String), ToolError> {
        let bytes = tokio::fs::read(path)
            .await
            .map_err(|e| ToolError::execution_failed(format!("Failed to read image file: {e}")))?;

        let mime_type = Self::detect_mime_type(path)?;
        let base64_data = BASE64.encode(&bytes);
        Ok((base64_data, mime_type))
    }

    fn resolve_image_path(workspace: &Path, image_path: &str) -> Result<PathBuf, ToolError> {

View on GitHub (pinned to 73e0f67d83)