gofr-dev/gofr · error
unexpected result type from circuit breaker
Error message
unexpected result type from circuit breaker
What it means
ErrUnexpectedCircuitBreakerResultType is returned by (*circuitBreaker).handleCircuitBreakerResult when the value stored in the breaker's result channel is not an *http.Response even though err was nil. It guards the internal goroutine/typed-result contract of the circuit breaker implementation.
Source
Thrown at pkg/gofr/service/circuit_breaker.go:20
import (
"context"
"errors"
"net/http"
"sync"
"time"
)
// circuitBreaker states.
const (
ClosedState = iota
OpenState
)
var (
// ErrCircuitOpen indicates that the circuit breaker is open.
ErrCircuitOpen = errors.New("unable to connect to server at host")
ErrUnexpectedCircuitBreakerResultType = errors.New("unexpected result type from circuit breaker")
)
// CircuitBreakerConfig holds the configuration for the circuitBreaker.
type CircuitBreakerConfig struct {
Threshold int // Threshold represents the max no of retry before switching the circuit breaker state.
Interval time.Duration // Interval represents the time interval duration between hitting the HealthURL
}
// circuitBreaker represents a circuit breaker implementation.
type circuitBreaker struct {
mu sync.RWMutex
state int // ClosedState or OpenState
failureCount int
threshold int
interval time.Duration
lastChecked time.Time
metrics Metrics
serviceName stringView on GitHub (pinned to 187eb24962)
Solutions
- Pin/upgrade to a gofr version where the circuit breaker result type is consistent; check the changelog for circuit_breaker.go fixes
- Don't call the breaker's internals directly — always go through the service's doRequest/executeWithCircuitBreaker API
- If reproducible, file a bug with a minimal reproduction including the CircuitBreakerConfig and call pattern
- Wrap the call and use errors.Is(err, ErrUnexpectedCircuitBreakerResultType) to distinguish it from real network failures
Defensive patterns
Strategy: type-guard
Validate before calling
resp, err := svc.doRequest(ctx, req)
if errors.Is(err, ErrUnexpectedCircuitBreakerResultType) {
// internal breaker contract violation: treat as non-retryable bug
} Type guard
func isUnexpectedBreakerResult(err error) bool { return errors.Is(err, ErrUnexpectedCircuitBreakerResultType) } Try / catch
resp, err := svc.Get(ctx, url)
if err != nil {
if errors.Is(err, ErrUnexpectedCircuitBreakerResultType) {
log.Error("circuit breaker returned invalid result; report bug")
return err // do not retry
}
return err
} Prevention
- Only use the public service API (doRequest/Get/Post), never breaker internals
- Keep gofr updated; check changelog for circuit breaker fixes
- If reproducible, file a minimal reproduction bug with your CircuitBreakerConfig
- Distinguish this sentinel from ErrCircuitOpen in error handling branches
When it happens
Trigger: executeWithCircuitBreaker submits the request to the breaker, whose internal result comes back through an any-typed channel; a failed type assertion result.(*http.Response) with err==nil makes handleCircuitBreakerResult return this error. In practice it indicates an internal bug or misuse of the breaker's execution path rather than a caller mistake.
Common situations: Concurrent modifications or custom code paths feeding unexpected values into the breaker's result; library upgrades that changed the internal result contract; race conditions between the request goroutine and the breaker state machine.
Related errors
- unable to connect to server at host
- MaxIdleConns cannot be negative
- MaxIdleConnsPerHost cannot be negative
- IdleConnTimeout cannot be negative
- %w, got: %d
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/896769c36d4f5034.
Report an issue: GitHub.