{"record":{"id":"810e8e65415255db","repo":"xai-org/grok-build","slug":"send-with-retry-escaping-pool-ran-at-least-one-att","errorCode":null,"errorMessage":"send_with_retry_escaping_pool ran at least one attempt","messagePattern":"send_with_retry_escaping_pool ran at least one attempt","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-http/src/lib.rs","lineNumber":553,"sourceCode":"                        pooled.clone()\n                    }\n                },\n            }\n        } else {\n            pooled.clone()\n        };\n        match op(client).await {\n            Ok(value) => return Ok(value),\n            Err(e) if is_retryable(&e) => {\n                // A silent retry would hide a degrading pool\n                tracing::debug!(attempt, error = %e, \"send_with_retry_escaping_pool: retrying after transient failure\");\n                last_err = Some(e);\n            }\n            Err(e) => return Err(e),\n        }\n    }\n\n    Err(last_err.expect(\"send_with_retry_escaping_pool ran at least one attempt\"))\n}\n\n/// Shared blocking client for startup fetches.\n/// Carries `STARTUP_FETCH_TIMEOUT` as the connect and read ceiling; do not reuse for long-lived requests.\n///\n/// This avoids redundant TLS certificate loading for blocking HTTP calls (e.g., model prefetching during startup).\n/// The blocking client is separate from the async `shared_client()` because reqwest's blocking client creates its own internal tokio runtime.\n///\n/// Mirrors `shared_client()`'s pool self-healing for the same reason: this client is reused (settings, prefetch).\n/// Idle and TCP eviction drops a connection before the upstream idle window (~60-100s; 30s is a conservative default) closes it.\n/// The HTTP/2 keepalive-ping setters that `shared_client()` uses are not exposed on reqwest's blocking `ClientBuilder` (0.12).\n/// Only the idle and TCP eviction half applies here.\npub fn shared_startup_blocking_client() -> reqwest::blocking::Client {\n    static BLOCKING_CLIENT: OnceLock<reqwest::blocking::Client> = OnceLock::new();\n    BLOCKING_CLIENT\n        .get_or_init(|| {\n            let _timer = startup_timer!(\"startup.http_blocking_client_build\");\n            xai_grok_extra_ca::build_blocking_reqwest_client(|builder| {","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-http/src/lib.rs#L535-L571","documentation":"send_with_retry_escaping_pool runs a retry loop tracking last_err and at the end returns Err(last_err.expect(\"send_with_retry_escaping_pool ran at least one attempt\")). The expect is an invariant assertion: if the loop exits without any recorded error, zero attempts ran, which the API contract forbids. It panics rather than returning a bogus Ok/Err.","triggerScenarios":"Calling send_with_retry_escaping_pool with a retry policy whose attempt count is 0 (or a config that computes zero attempts), so the loop body never executes and last_err is still None at return.","commonSituations":"A retry policy loaded from config/env where max_attempts defaults to 0 or parses to 0; an off-by-one in custom retry logic (attempts-1); wiring a policy object intended for a different function.","solutions":["Clamp the retry policy to at least one attempt before calling (max(1))","Fix the config/env source so max_attempts is >= 1 and validate it at load time","If you truly want zero attempts, skip the call instead of invoking the retry wrapper","Add an assertion/log where the policy is constructed to catch 0-attempt policies early"],"exampleFix":"// before\nlet policy = RetryPolicy { max_attempts: cfg.max_attempts }; // may be 0\nsend_with_retry_escaping_pool(&req, policy)?;\n// after\nlet policy = RetryPolicy { max_attempts: cfg.max_attempts.max(1) };\nsend_with_retry_escaping_pool(&req, policy)?;","handlingStrategy":"validation","validationCode":"assert!(retry_policy.max_attempts >= 1, \"retry policy must allow at least one attempt\");\nlet policy = RetryPolicy { max_attempts: retry_policy.max_attempts.max(1) };","typeGuard":"fn attempts_valid(p: &RetryPolicy) -> bool { p.max_attempts >= 1 }","tryCatchPattern":"let result = std::panic::catch_unwind(|| send_with_retry_escaping_pool(&req, policy))\n    .map_err(|_| anyhow!(\"retry policy yielded zero attempts\"))?;","preventionTips":["Clamp max_attempts to at least 1 where the policy is constructed","Validate retry config at load time (env/config parsing)","Never reuse a policy struct meant for a different retry API","Log the effective attempt count once at startup"],"tags":["http","retry","invariant","panics","rust"],"backgroundTag":"zero-retry-attempts","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}