AvaloniaUI/Avalonia · error · InvalidOperationException
{o.GetType()} belongs to a different compositor
Error message
{o.GetType()} belongs to a different compositor What it means
In GetServer for IBrush, when a CompositionBrush is encountered the helper checks that its Compositor matches the drawing compositor; a mismatch calls ThrowForeignCompositor. A composition object's server belongs to its own compositor's render loop and cannot be shared across two compositors/render threads.
Source
Thrown at src/Avalonia.Base/Rendering/Composition/Drawing/ServerResourceHelperExtensions.cs:55
if (compositor == null)
return pen;
if (pen == null)
return null;
if (pen is ImmutablePen immutable)
return immutable;
if (pen is ICompositionRenderResource<IPen> resource)
return resource.GetForCompositor(compositor);
ThrowNotCompatible(pen);
return null;
}
[MethodImpl(MethodImplOptions.NoInlining), DoesNotReturn]
static void ThrowNotCompatible(object o) =>
throw new InvalidOperationException(o.GetType() + " is not compatible with composition");
[MethodImpl(MethodImplOptions.NoInlining), DoesNotReturn]
static void ThrowForeignCompositor(CompositionObject o) =>
throw new InvalidOperationException(o.GetType() + " belongs to a different compositor");
public static ITransform? GetServer(this ITransform? transform, Compositor? compositor)
{
if (compositor == null)
return transform;
if (transform == null)
return null;
if (transform is ImmutableTransform immutable)
return immutable;
if (transform is ICompositionRenderResource<ITransform> resource)
resource.GetForCompositor(compositor);
return new ImmutableTransform(transform.Value);
}
public static IRenderDataGeometry? GetServer(this Geometry? geometry, Compositor? compositor)
{
if (geometry == null)
return null;View on GitHub (pinned to 11c5427268)
Solutions
- Create the CompositionBrush on the same Compositor that owns the drawing context.
- Per-compositor, recreate shared brushes rather than reusing one across compositors.
- Check brush.Compositor == targetCompositor before drawing, and recreate if not.
Example fix
// before var brush = compositorA.CreateColorBrush(color); // drawing on a surface backed by compositorB ctx.DrawRectangle(brush, null, rect); // throws: belongs to a different compositor // after var brush = compositorB.CreateColorBrush(color); ctx.DrawRectangle(brush, null, rect);
Defensive patterns
Strategy: validation
Validate before calling
if (brush is CompositionBrush cb && cb.Compositor != targetCompositor)
brush = targetCompositor.CreateColorBrush(/* same color */);
ctx.DrawRectangle(brush, null, rect); Type guard
static bool BelongsTo(CompositionObject o, Compositor c) => o.Compositor == c;
Try / catch
try { ctx.DrawRectangle(brush, null, rect); }
catch (InvalidOperationException ex) when (ex.Message.Contains("different compositor"))
{ brush = targetCompositor.CreateColorBrush(color); ctx.DrawRectangle(brush, null, rect); } Prevention
- Create CompositionBrushes on the same Compositor as the drawing context.
- Recreate shared brushes per-compositor instead of reusing one across windows.
- Check brush.Compositor == targetCompositor before drawing.
When it happens
Trigger: Drawing with a CompositionBrush that was created by a different Compositor than the one backing the current RenderDataDrawingContext.
Common situations: Sharing a CompositionBrush/visual across multiple top-level windows or surfaces that each have their own Compositor; caching a brush from one compositor and reusing it on another.
Related errors
- This resource doesn't exist on that compositor
- Composition visuals belong to different compositor instances
- There is no server-side counterpart for this object
- The object doesn't have an associated server counterpart
- Android backend wasn't initialized. Make sure .UseAndroid()
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/1ae31a64e86180d7.
Report an issue: GitHub.