{"record":{"id":"f0bebf9dc64ed4c7","repo":"abhigyanpatwari/GitNexus","slug":"llm-endpoint-circuit-open-retry-in-math-ceil-er","errorCode":null,"errorMessage":"LLM endpoint circuit open: retry in ${Math.ceil(err.retryAfterMs / 1000)}s. ${err.message}","messagePattern":"LLM endpoint circuit open: retry in (.+?)s\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/wiki/llm-client.ts","lineNumber":413,"sourceCode":"          ...authHeaders,\n        },\n        body: JSON.stringify(body),\n        // Request timeout is opt-in for wiki generation. Large local\n        // model runs can legitimately take well over a minute, so the\n        // default runtime path must not impose a hidden 60s ceiling.\n        signal:\n          config.requestTimeoutMs !== undefined\n            ? AbortSignal.timeout(config.requestTimeoutMs)\n            : undefined,\n      },\n      {\n        breakerKey: `wiki-llm-${new URL(url).host}`,\n        retry: { maxAttempts: config.maxAttempts ?? 3, baseDelayMs: 2_000, capDelayMs: 30_000 },\n      },\n    );\n  } catch (err) {\n    if (err instanceof CircuitOpenError) {\n      throw new Error(\n        `LLM endpoint circuit open: retry in ${Math.ceil(err.retryAfterMs / 1000)}s. ${err.message}`,\n      );\n    }\n    if (err instanceof ResilientFetchExhaustedError) {\n      const errorText = await err.response.text().catch(() => 'unknown error');\n      throw new Error(\n        `LLM API error (${err.response.status} after retries): ${errorText.slice(0, 500)}`,\n      );\n    }\n    if (config.requestTimeoutMs !== undefined && isTimeoutLikeError(err)) {\n      throw new Error(\n        `LLM request timed out after ${formatTimeoutDuration(config.requestTimeoutMs)}. ` +\n          'Increase --timeout or omit it to disable the request timeout.',\n      );\n    }\n    throw err;\n  }\n","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/wiki/llm-client.ts#L395-L431","documentation":"All LLM calls go through resilientFetch keyed by breakerKey `wiki-llm-<host>`. After repeated failures on that host the per-host circuit breaker opens and subsequent calls fail immediately with CircuitOpenError instead of hitting the endpoint; this error wraps it, telling you how long (retryAfterMs, shown in seconds) until the breaker half-opens. It means 'stop hammering, the endpoint is considered down', not that the latest single request failed.","triggerScenarios":"A run of wiki LLM calls to one API host fails repeatedly (5xx, 429, network errors) until the breaker trips; then the next callLLM invocation within the cooldown window throws this immediately. High `--concurrency` against a rate-limited or degraded endpoint trips it fastest.","commonSituations":"Rate limiting (429s) during a large wiki generation with parallel calls; an outage or degraded LLM gateway; on-prem proxy returning 502s; immediately rerunning after a failed run while the breaker (in-process) is still open in long-lived processes.","solutions":["Wait the indicated cooldown (retryAfterMs), then rerun — the breaker resets automatically","Address the upstream cause: check API status, rate limits, and reduce `--concurrency` (default 3)","If rate-limited, lower concurrency and/or request a higher rate limit or quota","In a fresh process the breaker starts closed, so rerunning the CLI after fixing the endpoint works immediately"],"exampleFix":"# before\ngitnexus wiki --concurrency 8   # trips breaker under 429s\n\n# after\ngitnexus wiki --concurrency 2   # retry after cooldown window","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await callLLM(prompt, config);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('circuit open: retry in')) {\n    const waitMs = Number(err.message.match(/retry in (\\d+)s/)?.[1] ?? 30) * 1000;\n    await sleep(waitMs + 1000); // breaker half-opens; retry once\n    return callLLM(prompt, config);\n  }\n  throw err;\n}","preventionTips":["Keep --concurrency modest (default 3) when the provider rate-limits","Back off on first 429/5xx signals instead of pushing through the whole retry budget","Treat 'circuit open' as a cooldown, not an error to log-and-retry immediately"],"tags":["llm","circuit-breaker","rate-limit","resilience","network","gitnexus"],"backgroundTag":"circuit-breaker-open","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}