{"record":{"id":"ac4cafcf6ffa05a1","repo":"janhq/jan","slug":"failed-to-create-fallback-client","errorCode":null,"errorMessage":"Failed to create fallback client","messagePattern":"Failed to create fallback client","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src-tauri/src/core/server/proxy.rs","lineNumber":2728,"sourceCode":"\n                // Transform body to OpenAI format for fallback\n                if let Some((url, openai_body)) = fallback_url.zip(fallback_body).and_then(|(url, body)| {\n                    let json_body = serde_json::from_slice::<serde_json::Value>(&body).ok()?;\n                    match transform_anthropic_to_openai(&json_body) {\n                        Some(transformed) => Some((url, transformed)),\n                        None => {\n                            log::error!(\"transform_anthropic_to_openai returned None for body: {json_body}\");\n                            None\n                        }\n                    }\n                }) {\n                    let chat_url = format!(\"{}/chat/completions\", url);\n                    log::info!(\"Fallback to chat completions: {chat_url}\");\n\n                    // Create a fresh client for the fallback to avoid connection pool issues\n                    let fallback_client = Client::builder()\n                        .build()\n                        .expect(\"Failed to create fallback client\");\n\n                    let mut fallback_req = fallback_client.post(&chat_url);\n\n                    // Ensure Content-Type is set and prevent compression\n                    fallback_req = fallback_req.header(\"Content-Type\", \"application/json\");\n                    fallback_req = fallback_req.header(\"Accept-Encoding\", \"identity\");\n\n                    for (name, value) in headers.iter() {\n                        if name != hyper::header::HOST\n                            && name != hyper::header::AUTHORIZATION\n                            && name != \"content-type\"\n                            && name != hyper::header::CONTENT_LENGTH\n                            && name != hyper::header::ACCEPT_ENCODING\n                        {\n                            fallback_req = fallback_req.header(name, value);\n                        }\n                    }\n                    if let Some(key) = fallback_api_key {","sourceCodeStart":2710,"sourceCodeEnd":2746,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/src-tauri/src/core/server/proxy.rs#L2710-L2746","documentation":"This is a panic (.expect) from reqwest::Client::builder().build() inside the Anthropic-to-OpenAI fallback path of the proxy server. Client::build() fails when the TLS backend cannot be initialized — on Linux this usually means native-tls cannot find CA certificates (no ca-certificates package, no SSL_CERT_FILE env var). The fallback creates a fresh client to avoid connection pool contamination from the primary request.","triggerScenarios":"Running on Linux without ca-certificates installed (minimal Docker images, Alpine without ca-certificates-bundle). The SSL_CERT_FILE or SSL_CERT_DIR env vars point to nonexistent paths. A corrupt system trust store. TLS backend initialization failure due to a FIPS or hardware crypto module issue.","commonSituations":"Docker Alpine images missing `apk add ca-certificates`. Distroless containers without root certificates. Proxied environments where MITM certs are not in the trust store. FIPS-mode kernels rejecting the TLS cipher negotiation.","solutions":["Install CA certificates: Debian/Ubuntu `apt-get install ca-certificates`, Alpine `apk add ca-certificates`.","Set SSL_CERT_FILE to the correct CA bundle path.","Use rustls TLS backend instead of native-tls in the reqwest feature flags.","Replace .expect with a proper error to avoid crashing the proxy."],"exampleFix":"// before\nlet fallback_client = Client::builder()\n    .build()\n    .expect(\"Failed to create fallback client\");\n\n// after\nlet fallback_client = Client::builder()\n    .build()\n    .map_err(|e| format!(\"Failed to create fallback client: {e}\"))?;","handlingStrategy":"try-catch","validationCode":"// At startup, verify a reqwest client can be built\nfn verify_tls_available() -> bool {\n    reqwest::Client::builder().build().is_ok()\n}\n\n// If false, log a clear message about missing CA certificates\nif !verify_tls_available() {\n    log::error!(\"reqwest client build failed; install ca-certificates and check SSL_CERT_FILE\");\n}","typeGuard":null,"tryCatchPattern":"// Replace .expect with a proper error\nlet fallback_client = Client::builder()\n    .build()\n    .map_err(|e| {\n        log::error!(\"Failed to create fallback HTTP client: {e}\");\n        format!(\"TLS/client init failed: {e}. Check CA certificates.\")\n    })?;","preventionTips":["Install ca-certificates in all Docker/container images.","Set SSL_CERT_FILE to the correct CA bundle path.","Prefer rustls over native-tls in reqwest features to avoid system cert issues.","Build the client once at startup and reuse it instead of per-request construction.","Replace .expect with .map_err in production proxy code."],"tags":["panic","reqwest","tls","ca-certificates","proxy","fallback"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}