App-vNext/Polly · error · ObjectDisposedException

This resilience pipeline has been disposed and cannot be use

Error message

This resilience pipeline has been disposed and cannot be used anymore.

What it means

ResiliencePipeline wraps its component in a ComponentDisposeHelper that tracks a _disposed flag; EnsureNotDisposed throws ObjectDisposedException once disposed. Every execution first calls EnsureNotDisposed, so using a pipeline after DisposeAsync/Dispose reclaims its underlying strategies is blocked.

Source

Thrown at src/Polly.Core/Utils/Pipeline/ComponentDisposeHelper.cs:33

    public ValueTask DisposeAsync()
    {
        if (EnsureDisposable())
        {
            return ForceDisposeAsync();
        }

        return default;
    }

    public void EnsureNotDisposed()
    {
        if (_disposed)
        {
            ThrowDisposed();
        }
    }

    private static void ThrowDisposed() => throw new ObjectDisposedException("ResiliencePipeline", "This resilience pipeline has been disposed and cannot be used anymore.");

    public ValueTask ForceDisposeAsync()
    {
        _disposed = true;
        return _component.DisposeAsync();
    }

    private bool EnsureDisposable()
    {
        if (_disposeBehavior == DisposeBehavior.Ignore)
        {
            return false;
        }

        if (_disposeBehavior == DisposeBehavior.Reject)
        {
            throw new InvalidOperationException("Disposing this resilience pipeline is not allowed because it is owned by the pipeline registry.");
        }

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Do not dispose the pipeline until all in-flight and future executions have completed; track its lifetime explicitly.
  2. If using 'using'/await using, ensure the scope encloses all usage including awaited continuations.
  3. For registry-managed pipelines, do not dispose the pipeline yourself; let the registry own it.

Example fix

// before
await using var pipeline = builder.Build();
// ... pipeline goes out of scope ...
await pipeline.ExecuteAsync(work); // ObjectDisposedException

// after
var pipeline = builder.Build();
try { await pipeline.ExecuteAsync(work); }
finally { await pipeline.DisposeAsync(); }
Defensive patterns

Strategy: try-catch

Try / catch

try { await pipeline.ExecuteAsync(work); }
catch (ObjectDisposedException) {
    // obtain a fresh pipeline or report shutdown
}

Prevention

When it happens

Trigger: Calling pipeline.Execute(...)/ExecuteAsync(...) after the pipeline has been disposed. This includes pipelines you explicitly disposed and those whose DisposeBehavior allowed disposal.

Common situations: Disposing a pipeline held in a field while a concurrent request still uses it; using a 'using var pipeline' that disposes before an async continuation resumes; disposing a registry-owned pipeline reference after the registry disposed it.

Related errors


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