{"record":{"id":"6a0bf104e6f9358d","repo":"App-vNext/Polly","slug":"this-resilience-pipeline-has-been-disposed-and-can","errorCode":null,"errorMessage":"This resilience pipeline has been disposed and cannot be used anymore.","messagePattern":"This resilience pipeline has been disposed and cannot be used anymore\\.","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Polly.Core/Utils/Pipeline/ComponentDisposeHelper.cs","lineNumber":33,"sourceCode":"    public ValueTask DisposeAsync()\n    {\n        if (EnsureDisposable())\n        {\n            return ForceDisposeAsync();\n        }\n\n        return default;\n    }\n\n    public void EnsureNotDisposed()\n    {\n        if (_disposed)\n        {\n            ThrowDisposed();\n        }\n    }\n\n    private static void ThrowDisposed() => throw new ObjectDisposedException(\"ResiliencePipeline\", \"This resilience pipeline has been disposed and cannot be used anymore.\");\n\n    public ValueTask ForceDisposeAsync()\n    {\n        _disposed = true;\n        return _component.DisposeAsync();\n    }\n\n    private bool EnsureDisposable()\n    {\n        if (_disposeBehavior == DisposeBehavior.Ignore)\n        {\n            return false;\n        }\n\n        if (_disposeBehavior == DisposeBehavior.Reject)\n        {\n            throw new InvalidOperationException(\"Disposing this resilience pipeline is not allowed because it is owned by the pipeline registry.\");\n        }","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly.Core/Utils/Pipeline/ComponentDisposeHelper.cs#L15-L51","documentation":"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.","triggerScenarios":"Calling pipeline.Execute(...)/ExecuteAsync(...) after the pipeline has been disposed. This includes pipelines you explicitly disposed and those whose DisposeBehavior allowed disposal.","commonSituations":"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.","solutions":["Do not dispose the pipeline until all in-flight and future executions have completed; track its lifetime explicitly.","If using 'using'/await using, ensure the scope encloses all usage including awaited continuations.","For registry-managed pipelines, do not dispose the pipeline yourself; let the registry own it."],"exampleFix":"// before\nawait using var pipeline = builder.Build();\n// ... pipeline goes out of scope ...\nawait pipeline.ExecuteAsync(work); // ObjectDisposedException\n\n// after\nvar pipeline = builder.Build();\ntry { await pipeline.ExecuteAsync(work); }\nfinally { await pipeline.DisposeAsync(); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await pipeline.ExecuteAsync(work); }\ncatch (ObjectDisposedException) {\n    // obtain a fresh pipeline or report shutdown\n}","preventionTips":["Do not dispose a pipeline while in-flight or future executions may still use it.","Ensure 'await using'/'using' scopes enclose all usage including awaited continuations.","For shared pipelines, manage lifetime centrally rather than per-consumer."],"tags":["pipeline","disposed","object-disposed","lifetime","polly-core"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}