googleworkspace/cli · critical · GwsError

5

5

Error message

Failed to build HTTP client: {e}

What it means

`build_client_inner()` failed: `reqwest::Client::builder()...build()` returned an error before any request was made. With this builder configuration (default headers + a 10s-class connect timeout) the realistic failure modes are TLS-backend initialization (native-tls/OpenSSL load failure or rustls provider init problem) and system DNS-resolver initialization failure. Everything in gws that talks HTTP goes through this client, so the first network-touching command of a session fails here.

Source

Thrown at crates/google-workspace/src/client.rs:46

    let mut headers = HeaderMap::new();
    let name = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");

    // Format: gl-rust/name-version (the gl-rust/ prefix is fixed)
    let client_header = format!("gl-rust/{}-{}", name, version);
    if let Ok(header_value) = HeaderValue::from_str(&client_header) {
        headers.insert("x-goog-api-client", header_value);
    }

    reqwest::Client::builder()
        .default_headers(headers)
        .connect_timeout(std::time::Duration::from_secs(CONNECT_TIMEOUT_SECS))
        .build()
        .map_err(|e| format!("Failed to build HTTP client: {e}"))
}

pub fn build_client() -> Result<reqwest::Client, crate::error::GwsError> {
    build_client_inner().map_err(|message| crate::error::GwsError::Other(anyhow::anyhow!(message)))
}

/// Returns a shared reqwest client clone backed by a single global connection pool.
///
/// `reqwest::Client` is cheap to clone, so callers can take ownership of the
/// returned value while still sharing pooled connections underneath.
pub fn shared_client() -> Result<reqwest::Client, crate::error::GwsError> {
    static CLIENT: OnceLock<Result<reqwest::Client, String>> = OnceLock::new();

    match CLIENT.get_or_init(build_client_inner) {
        Ok(client) => Ok(client.clone()),
        Err(message) => Err(crate::error::GwsError::Other(anyhow::anyhow!(
            message.clone()
        ))),
    }
}

/// Send an HTTP request with automatic retry on 429 (rate limit) responses

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Run `ldd $(which gws)` and install the matching OpenSSL runtime (e.g. `apt install libssl3`) if a symbol is unresolved.
  2. In minimal containers, add ca-certificates and ensure /etc/resolv.conf exists.
  3. Prefer the statically-linked release artifacts (or rustls-TLS builds) for portable deployment.
  4. Verify with a trivial call (`gws auth status`) after fixing — the error surfaces on first client construction.

Example fix

# before — binary copied onto a host with old OpenSSL
./gws drive files list
# -> Failed to build HTTP client: failed to init TLS backend

# after — install matching runtime libs / CA bundle, or ship the static binary
apt-get install -y libssl3 ca-certificates
./gws drive files list
Defensive patterns

Strategy: try-catch

Validate before calling

// Fail fast at startup instead of mid-command
fn http_stack_ok() -> bool {
    google_workspace::client::build_client().is_ok()
}

Try / catch

let client = match google_workspace::client::build_client() {
    Ok(c) => c,
    Err(GwsError::Other(e)) if e.to_string().contains("Failed to build HTTP client") => {
        eprintln!("TLS/resolver init failed — check OpenSSL libs, ca-certificates, and /etc/resolv.conf");
        std::process::exit(3);
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Running the gws binary on a host whose OpenSSL shared libraries are missing or the wrong major version (native-tls builds); a musl/alpine image lacking ca-certificates; a system where getaddrinfo/resolver init fails (no /etc/resolv.conf in a minimal container); an OS/cert-store incompatibility after a distro upgrade.

Common situations: Copying the binary between distros with different OpenSSL (libssl3 vs 1.1); scratch/distroless containers missing CA bundles and resolver config; Nix/GNU Guix dynamic-linking mismatches; stripped-down VMs.

Related errors


AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16). Data as JSON: /api/errors/02f0786183fa55fd. Report an issue: GitHub.