Zackriya-Solutions/meetily · error · anyhow::Error

Failed to create download client: {}

Error message

Failed to create download client: {}

What it means

download_model_with_owner builds an HTTP client via reqwest's Client::builder() (with a Meetily/... user agent) before fetching the model. If reqwest fails to construct the client — almost always TLS backend initialization failure (e.g. rustls or native-tls/openssl can't initialize, missing root store, or invalid default TLS configuration) — the builder's error is wrapped in this anyhow message and the download aborts before any network request.

Source

Thrown at frontend/src-tauri/src/whisper_engine/whisper_engine.rs:1146

        }

        if !self.models_dir.exists() {
            fs::create_dir_all(&self.models_dir)
                .await
                .map_err(|e| anyhow!("Failed to create models directory: {}", e))?;
        }

        {
            let mut models = self.available_models.write().await;
            if let Some(model_info) = models.get_mut(model_name) {
                model_info.status = ModelStatus::Downloading { progress: 0 };
            }
        }

        let client = Client::builder()
            .user_agent(concat!("Meetily/", env!("CARGO_PKG_VERSION")))
            .build()
            .map_err(|e| anyhow!("Failed to create download client: {}", e))?;
        let response = tokio::select! {
            biased;
            _ = active_download.cancellation.cancelled() => return Err(DownloadCancelled.into()),
            response = client.get(model_url).send() => response
                .map_err(|e| anyhow!("Failed to start download: {}", e))?,
        };

        if !response.status().is_success() {
            return Err(anyhow!("Download failed with status: {}", response.status()));
        }

        let total_size = response.content_length().unwrap_or(0);
        let mut file = fs::File::create(file_path)
            .await
            .map_err(|e| anyhow!("Failed to create file: {}", e))?;

        use futures_util::StreamExt;
        let mut stream = response.bytes_stream();

View on GitHub (pinned to a2cb62e827)

Solutions

  1. Check the wrapped error text after the colon — it names the real cause (TLS/crypto provider, OpenSSL, etc.) and fix that first.
  2. If using rustls 0.23 with multiple crypto providers, install one explicitly at startup: rustls::crypto::ring::default_provider().install_default().
  3. On Linux, install OpenSSL development packages (libssl-dev) or switch Cargo features to the rustls TLS backend.
  4. Ensure CA certificates exist in the environment (ca-certificates package on Alpine/slim containers).
  5. Align reqwest features in Cargo.toml with the intended TLS backend and rebuild cleanly (cargo clean) to remove stale linking.

Example fix

// before: relies on default crypto provider, fails when 2 are linked
let client = Client::builder()
    .user_agent(concat!("Meetily/", env!("CARGO_PKG_VERSION")))
    .build()
    .map_err(|e| anyhow!("Failed to create download client: {}", e))?;
// after: install a concrete rustls provider before building any client
rustls::crypto::ring::default_provider()
    .install_default()
    .expect("failed to install rustls crypto provider");
let client = Client::builder()
    .user_agent(concat!("Meetily/", env!("CARGO_PKG_VERSION")))
    .build()
    .map_err(|e| anyhow!("Failed to create download client: {}", e))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// at app startup, fail fast if the TLS stack can't init
fn http_stack_ok() -> bool {
    reqwest::Client::builder().build().is_ok()
}
if !http_stack_ok() {
    eprintln!("HTTP/TLS stack unavailable; model downloads disabled");
}

Try / catch

let client = reqwest::Client::builder()
    .user_agent(concat!("Meetily/", env!("CARGO_PKG_VERSION")))
    .build()
    .map_err(|e| {
        eprintln!("client build failed: {e}"); // surface TLS root cause
        anyhow!("Failed to create download client: {}", e)
    })?;

Prevention

When it happens

Trigger: Client::builder().user_agent(...).build() returns Err: TLS backend init failure (openssl not linked, rustls without a crypto provider installed when multiple ring/aws-lc-rs versions are linked), invalid global default settings, or resource exhaustion during client construction.

Common situations: Building on Linux without OpenSSL dev headers when the native-tls feature is enabled; a dependency bump links two rustls crypto providers so no default is installed (rustls 0.23 'no process-level CryptoProvider' panic/error); stripped-down container/distro missing CA certificates that the TLS layer requires at init.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@a2cb62e827 (2026-09-12). Data as JSON: /api/errors/d4b85bbf20b1d9ad. Report an issue: GitHub.