App-vNext/Polly · error · InvalidOperationException

This instance of 'CircuitBreakerStateProvider' is already…

Error message

This instance of 'CircuitBreakerStateProvider' is already initialized and cannot be used in a different circuit-breaker strategy.

What it means

A CircuitBreakerStateProvider instance can be bound to exactly one circuit-breaker strategy. The binding happens lazily during ResiliencePipelineBuilder.Build() via the internal Initialize() method, which refuses to overwrite a non-null _circuitStateProvider. Passing the same provider instance into two different CircuitBreakerStrategyOptions causes the second Build() to throw this InvalidOperationException. It protects the provider from reporting the wrong circuit's state.

Solutions

  1. Create a new CircuitBreakerStateProvider instance for each circuit-breaker strategy instead of reusing one.
  2. If you need one logical view over several circuits, keep a dictionary of providers (one per circuit name) rather than sharing a single instance.
  3. Audit all CircuitBreakerStrategyOptions declarations to confirm no two reference the same StateProvider object reference.

Example fix

// before
var provider = new CircuitBreakerStateProvider();
optionsA.StateProvider = provider;
optionsB.StateProvider = provider; // throws on second Build()

// after
optionsA.StateProvider = new CircuitBreakerStateProvider();
optionsB.StateProvider = new CircuitBreakerStateProvider();
Defensive patterns

Strategy: validation

Validate before calling

// Before Build(), ensure the provider is not already bound:
if (provider.IsInitialized) {
    throw new InvalidOperationException("Provider already bound to another circuit; create a new instance.");
}
// Then assign and build. Track providers in a per-circuit dictionary.

Prevention

When it happens

Trigger: Instantiating one CircuitBreakerStateProvider, assigning it to optionsA.StateProvider and optionsB.StateProvider (two separate CircuitBreakerStrategyOptions), then calling Build() on both builders. Also reusing a provider after a pipeline built with it has been constructed.

Common situations: Sharing a 'watcher' object across multiple named circuits in DI; refactoring a single circuit into two and forgetting to give each its own provider; copying options via memberwise clone that aliases the StateProvider reference.

Related errors


AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13). Data as JSON: /api/errors/e26ae6145d950604. Report an issue: GitHub.

Appendix: source

Thrown at src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs:14

namespace Polly.CircuitBreaker;

/// <summary>
/// Allows retrieval of the circuit breaker state.
/// </summary>
public sealed class CircuitBreakerStateProvider
{
    private Func<CircuitState>? _circuitStateProvider;

    internal void Initialize(Func<CircuitState> circuitStateProvider)
    {
        if (_circuitStateProvider != null)
        {
            throw new InvalidOperationException($"This instance of '{nameof(CircuitBreakerStateProvider)}' is already initialized and cannot be used in a different circuit-breaker strategy.");
        }

        _circuitStateProvider = circuitStateProvider;
    }

    /// <summary>
    /// Gets a value indicating whether the state provider is initialized.
    /// </summary>
    /// <remarks>
    /// The initialization happens when the circuit-breaker strategy is attached to this class.
    /// This happens when the final strategy is created by the <see cref="ResiliencePipelineBuilder.Build"/> call.
    /// </remarks>
    internal bool IsInitialized => _circuitStateProvider != null;

    /// <summary>
    /// Gets the state of the underlying circuit.
    /// </summary>
    public CircuitState CircuitState => _circuitStateProvider?.Invoke() ?? CircuitState.Closed;

View on GitHub (pinned to d0e46bdb1e)