{"record":{"id":"783fd8721961ed2c","repo":"ruvnet/ruflo","slug":"circuit-breaker-open-for-provider-provider","errorCode":null,"errorMessage":"Circuit breaker open for provider: ${provider}","messagePattern":"Circuit breaker open for provider: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"v3/@claude-flow/integration/src/multi-model-router.ts","lineNumber":579,"sourceCode":"    let provider = request.provider;\n    let model = request.model;\n\n    if (!provider || !model) {\n      const routing = await this.route({\n        task: 'completion',\n        messages: request.messages,\n        requiredCapabilities: {\n          supportsTools: request.tools !== undefined,\n          supportsJson: request.responseFormat === 'json',\n        },\n      });\n      provider = routing.provider;\n      model = routing.model;\n    }\n\n    // Check circuit breaker\n    if (this.isCircuitOpen(provider)) {\n      throw new Error(`Circuit breaker open for provider: ${provider}`);\n    }\n\n    const startTime = performance.now();\n\n    try {\n      // Execute completion via provider API\n      const response = await this.executeCompletion(request, provider, model);\n\n      // Update health\n      this.recordSuccess(provider, performance.now() - startTime);\n\n      // Update cost tracker\n      this.trackCost(provider, model, response.cost, response.usage);\n\n      // Cache response\n      if (this.config.cacheTTL && !request.stream) {\n        this.cache.set(cacheKey, {\n          response,","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/integration/src/multi-model-router.ts#L561-L597","documentation":"Thrown by MultiModelRouter before executing a completion (v3/@claude-flow/integration/src/multi-model-router.ts:579) when the selected provider's circuit breaker is open. recordFailure() opens the circuit once failureCount reaches circuitBreaker.failureThreshold (default 5, multi-model-router.ts:463/1020) and a setTimeout resets it after circuitBreaker.resetTimeout, emitting a 'circuit:open' event. The throw means: this provider recently failed repeatedly, so the router refuses to send more traffic to it right now.","triggerScenarios":"A provider (OpenAI, Anthropic, etc.) returning 5xx/429/network errors five times in a row; API key revoked or quota exhausted producing consistent failures; downstream outage while your code keeps calling complete() — each call fails fast with this error until resetTimeout elapses.","commonSituations":"Expired/invalid API key causing every attempt to fail until the breaker trips; rate limiting (429s) counted as failures; regional outage; too-low failureThreshold with flaky networks; tests hammering a mocked-down provider.","solutions":["Fix the underlying provider failure first — check the key, quota, and provider status page; the breaker is a symptom, not the cause.","Retry after circuitBreaker.resetTimeout (the circuit auto-half-opens via the scheduled reset) with backoff instead of immediate retries.","Enable fallback routing so requests go to another healthy provider while one circuit is open (listen for the 'circuit:open' event and reroute).","Tune circuitBreaker.failureThreshold / resetTimeout (and consider treating 429 as backoff rather than failure) so transient blips do not trip the breaker."],"exampleFix":"// before\nconst res = await router.complete(request); // throws while circuit open\n\n// after\ntry {\n  const res = await router.complete(request);\n} catch (e) {\n  if ((e as Error).message.startsWith('Circuit breaker open')) {\n    await sleep(resetTimeoutMs); // wait for the scheduled reset\n    return router.complete(request);\n  }\n  throw e;\n}","handlingStrategy":"fallback","validationCode":"router.on('circuit:open', ({ provider }) => {\n  disabledProviders.add(provider); // consult before routing\n});\n// before calling complete(): route around providers in disabledProviders","typeGuard":"function isCircuitBreakerError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('Circuit breaker open for provider:');\n}","tryCatchPattern":"try {\n  return await router.complete(request);\n} catch (e) {\n  if (isCircuitBreakerError(e)) {\n    await sleep(resetTimeoutMs); // circuit auto-resets via scheduled timeout\n    return router.complete(request);\n  }\n  throw e;\n}","preventionTips":["Fix root-cause provider failures (keys, quota, network) — the breaker only reflects them.","Listen to 'circuit:open' events and reroute to healthy providers instead of retrying the same one.","Tune failureThreshold/resetTimeout and classify 429s as backoff, not hard failures.","Back off while the circuit is open; hammering complete() just fails fast every time."],"tags":["circuit-breaker","provider-outage","resilience","llm","retry"],"backgroundTag":"circuit-breaker-open","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}