{"record":{"id":"b55b835b1bf9f0da","repo":"App-vNext/Polly","slug":"disposing-this-resilience-pipeline-is-not-allowed","errorCode":null,"errorMessage":"Disposing this resilience pipeline is not allowed because it is owned by the pipeline registry.","messagePattern":"Disposing this resilience pipeline is not allowed because it is owned by the pipeline registry\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Polly.Core/Utils/Pipeline/ComponentDisposeHelper.cs","lineNumber":50,"sourceCode":"\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        }\n\n        return !_disposed;\n    }\n}\n","sourceCodeStart":32,"sourceCodeEnd":56,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly.Core/Utils/Pipeline/ComponentDisposeHelper.cs#L32-L56","documentation":"When ComponentDisposeHelper is constructed with DisposeBehavior.Reject, DisposeAsync throws InvalidOperationException. Pipelines resolved from ResiliencePipelineRegistry are given Reject behavior because the registry owns their lifetime; calling Dispose on such a pipeline would double-dispose resources the registry still manages.","triggerScenarios":"Calling .Dispose()/.DisposeAsync() on a ResiliencePipeline obtained via registry.GetPipeline(...) or the DI ResiliencePipelineProvider, since those set Reject behavior.","commonSituations":"Treating a registry-resolved pipeline like a normally-owned one and wrapping it in 'using'; injecting a pipeline and disposing it in a consumer's Dispose; refactoring from a self-built pipeline (which you may dispose) to a registry-resolved one without removing the dispose call.","solutions":["Do not dispose pipelines that come from the registry/provider; let the registry manage their lifetime.","If you need a disposable pipeline, build it yourself with new ResiliencePipelineBuilder().AddStrategy(...).Build().","Inject IReadOnlyResiliencePipelineProvider or the pipeline without an owning contract so consumers cannot dispose it."],"exampleFix":"// before\nvar pipeline = registry.GetPipeline(\"k\");\nawait pipeline.DisposeAsync(); // throws: owned by registry\n\n// after\nvar pipeline = registry.GetPipeline(\"k\");\n// use freely; do NOT dispose. Dispose the registry instead at app shutdown.","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await pipeline.DisposeAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"pipeline registry\")) {\n    // ignore: registry owns this pipeline; nothing to do\n}","preventionTips":["Never dispose pipelines resolved from the registry/provider; dispose the registry at shutdown instead.","Inject pipelines as non-disposable contracts to consumers.","If you need a disposable pipeline, build it yourself via new ResiliencePipelineBuilder()."],"tags":["pipeline","registry","invalid-operation","lifetime","dispose","polly-core"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}