{"record":{"id":"cf480181844f9a8c","repo":"ruvnet/ruflo","slug":"circuit-breaker-is-open-service-temporarily-unava","errorCode":null,"errorMessage":"Circuit breaker is open. Service temporarily unavailable.","messagePattern":"Circuit breaker is open\\. Service temporarily unavailable\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/production/circuit-breaker.ts","lineNumber":116,"sourceCode":"\n      case 'open':\n        return false;\n\n      case 'half-open':\n        // Allow a percentage of requests through\n        return Math.random() < this.config.halfOpenRequestPercentage;\n\n      default:\n        return true;\n    }\n  }\n\n  /**\n   * Execute a function through the circuit breaker\n   */\n  async execute<T>(fn: () => Promise<T>): Promise<T> {\n    if (!this.isAllowed()) {\n      throw new Error('Circuit breaker is open. Service temporarily unavailable.');\n    }\n\n    this.totalRequests++;\n\n    try {\n      const result = await fn();\n      this.recordSuccess();\n      return result;\n    } catch (error) {\n      this.recordFailure();\n      throw error;\n    }\n  }\n\n  /**\n   * Record a successful operation\n   */\n  recordSuccess(): void {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/production/circuit-breaker.ts#L98-L134","documentation":"CircuitBreaker.execute() first calls isAllowed(); when the breaker is in OPEN state — or in HALF_OPEN and the request is randomly rejected per halfOpenRequestPercentage — it throws immediately WITHOUT invoking your function. The breaker reached OPEN because consecutive failures crossed the configured threshold within the monitoring window, so the library is fail-fasting to protect the downstream service and your latency.","triggerScenarios":"Calling execute() while the wrapped dependency (API, DB, provider) has been failing past the failure threshold; any call during the OPEN window before resetTimeout elapses; a subset of calls in HALF_OPEN probing state when halfOpenRequestPercentage < 100.","commonSituations":"A provider outage tripping the breaker, then every request failing instantly with this error even after the provider partially recovers; aggressive thresholds (low failureThreshold, short monitoringWindow) opening on transient blips; retry storms keeping the breaker open.","solutions":["Wait for resetTimeout — the breaker then moves to HALF_OPEN and lets probe traffic through.","Fix or verify the underlying service (the breaker opened for a reason: check failureCount/state metrics).","Catch this error and serve a fallback/degraded response instead of propagating (see defense below).","Tune config: raise failureThreshold, shorten resetTimeout for faster recovery, or set halfOpenRequestPercentage to 100 so half-open always probes."],"exampleFix":"// before\nconst data = await breaker.execute(() => fetchProvider(id)); // throws while open\n\n// after\nlet data;\ntry {\n  data = await breaker.execute(() => fetchProvider(id));\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Circuit breaker is open')) {\n    data = await cachedCopyOf(id); // degrade gracefully\n  } else throw e;\n}","handlingStrategy":"fallback","validationCode":"// Pre-flight: expose breaker state so callers can skip doomed calls\nfunction isCircuitLikelyOpen(breaker: { getState(): { state: 'closed' | 'open' | 'half-open'; failureCount: number } }): boolean {\n  return breaker.getState().state === 'open';\n}\nif (isCircuitLikelyOpen(breaker)) return cachedOrDefault(id); // don't even attempt while OPEN","typeGuard":"function isCircuitOpenError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('Circuit breaker is open');\n}","tryCatchPattern":"try {\n  return await breaker.execute(() => callService(id));\n} catch (e) {\n  if (isCircuitOpenError(e)) {\n    metrics.increment('service.degraded_fallback');\n    return cachedOrDefault(id); // serve stale/default — do NOT retry immediately, that defeats the breaker\n  }\n  throw e; // real failures propagate and are counted by recordFailure inside execute()\n}","preventionTips":["Always pair execute() with an open-circuit catch that serves a fallback — never propagate this error to end users.","Don't wrap execute() in a tight retry loop: retries during OPEN are rejected instantly and add noise, not recovery.","Expose breaker state (state, failureCount) in dashboards so 'suddenly everything fails fast' is diagnosable."],"tags":["circuit-breaker","resilience","availability","retry"],"backgroundTag":"circuit-breaker-open","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}