{"record":{"id":"5f73fd5e90782d8d","repo":"AvaloniaUI/Avalonia","slug":"platformdrawingcontext","errorCode":null,"errorMessage":"PlatformDrawingContext","messagePattern":"PlatformDrawingContext","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/PlatformDrawingContext.cs","lineNumber":110,"sourceCode":"    protected override void PushEffectCore(IEffect effect, Rect bounds)\n    {\n        if (_impl is IDrawingContextImplWithEffects effectImpl)\n        {\n            effectImpl.PushEffect(bounds.Inflate(effect.GetEffectOutputPadding()), effect);\n        }\n    }\n\n    protected override void PopClipCore() => _impl.PopClip();\n\n    protected override void PopGeometryClipCore() => _impl.PopGeometryClip();\n\n    protected override void PopOpacityCore() => _impl.PopOpacity();\n\n    protected override void PopOpacityMaskCore() => _impl.PopOpacityMask();\n\n    protected override void PopTransformCore() =>\n        _impl.Transform =\n            (_transforms ?? throw new ObjectDisposedException(nameof(PlatformDrawingContext))).Pop();\n\n    protected override void PopRenderOptionsCore() => _impl.PopRenderOptions();\n    \n    protected override void PopTextOptionsCore() => _impl.PopTextOptions();\n\n    /// <inheritdoc />\n    protected override void PopEffectCore()\n    {\n        if (_impl is IDrawingContextImplWithEffects effectImpl)\n        {\n            effectImpl.PopEffect();\n        }\n    }\n\n    protected override void DisposeCore()\n    {\n        if (_ownsImpl)\n            _impl.Dispose();","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/PlatformDrawingContext.cs#L92-L128","documentation":"Thrown by PopTransformCore when the _transforms stack is null at pop time. The stack is lazily allocated on the first PushTransformCore call; a null stack means no transform was ever pushed (so there is nothing to pop), or the context was already disposed (DisposeCore returns the stack to the pool and nulls the field).","triggerScenarios":"Calling PopTransform() without a matching PushTransform(); or calling PopTransform() after the drawing context has been disposed.","commonSituations":"Unbalanced transform push/pop in custom render overrides; an early-return or exception path that pops a transform that was never pushed; reusing a disposed DrawingContext.","solutions":["Match every PushTransform with exactly one PopTransform in the same scope.","Use a try/finally (or 'using (context.PushTransform(...))' if available) so a Pop always runs even on exception.","Do not call any Draw/Pop method on a DrawingContext after it is disposed."],"exampleFix":"// before\ncontext.PushTransform(matrix);\n// ... exception skips the pop ...\ncontext.PopTransform();\n\n// after\ncontext.PushTransform(matrix);\ntry\n{\n    // draw\n}\nfinally\n{\n    context.PopTransform();\n}","handlingStrategy":"validation","validationCode":"// Maintain a depth counter; only Pop when depth > 0.\nint transformDepth = 0;\nvoid SafePush(Matrix m) { context.PushTransform(m); transformDepth++; }\nvoid SafePop() { if (transformDepth > 0) { context.PopTransform(); transformDepth--; } }","typeGuard":null,"tryCatchPattern":"try { context.PopTransform(); }\ncatch (ObjectDisposedException) { /* context disposed or no push — reset state */ }","preventionTips":["Wrap Push/Pop in try/finally so Pop always runs.","Never Pop without a prior Push on the same context."],"tags":["avalonia","drawing-context","transform","disposed","unbalanced"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}