AvaloniaUI/Avalonia · error · ObjectDisposedException

ImmediateDrawingContext

Error message

ImmediateDrawingContext

What it means

The PushedState constructor throws ObjectDisposedException(nameof(ImmediateDrawingContext)) when context._states is null. _states is returned to the pool and nulled in Dispose(), so any push (PushTransform, PushClip, PushOpacity, etc.) attempted after the context is disposed fails here.

Solutions

  1. Do not use an ImmediateDrawingContext after Dispose(); scope all draws inside its using lifetime.
  2. Track disposal and short-circuit deferred draw operations.
  3. Obtain a fresh context per render pass instead of reusing one.

Example fix

// before
using (var ctx = ...CreateDrawingContext()) { /* ... */ }
ctx.PushTransform(m); // ctx already disposed -> throws

// after - keep all drawing inside the using scope
using (var ctx = ...CreateDrawingContext())
{
    ctx.PushTransform(m);
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no Push* call happens after the context is disposed.
if (ctx is null) return;
// Inside the using-scope only:
using (ctx.PushTransform(m)) { /* draw */ }

Prevention

When it happens

Trigger: Calling any Push* method on an ImmediateDrawingContext whose Dispose() already ran — e.g. using a context from a completed render or storing a context field that was disposed and then drawing later.

Common situations: Reusing a DrawingContext after the using-block exited; drawing from a background thread after the UI context was disposed; deferred draw operations that outlive the context.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/ad984d9d237f756f. Report an issue: GitHub.

Appendix: source

Thrown at src/Avalonia.Base/Media/ImmediateDrawingContext.cs:227

            private readonly ImmediateDrawingContext _context;
            private readonly Matrix _matrix;
            private readonly PushedStateType _type;

            public enum PushedStateType
            {
                None,
                Matrix,
                Opacity,
                Clip,
                MatrixContainer,
                GeometryClip,
                OpacityMask,
            }

            internal PushedState(ImmediateDrawingContext context, PushedStateType type, Matrix matrix = default)
            {
                if (context._states is null)
                    throw new ObjectDisposedException(nameof(ImmediateDrawingContext));

                _context = context;
                _type = type;
                _matrix = matrix;
                _level = context._currentLevel += 1;
                context._states.Push(this);
            }

            public void Dispose()
            {
                if (_type == PushedStateType.None)
                    return;
                if (_context._states is null || _context._transformContainers is null)
                    throw new ObjectDisposedException(nameof(DrawingContext));
                if (_context._currentLevel != _level)
                    throw new InvalidOperationException("Wrong Push/Pop state order");
                _context._currentLevel--;
                _context._states.Pop();

View on GitHub (pinned to 11c5427268)