AvaloniaUI/Avalonia · error · InvalidOperationException
Composition visuals belong to different compositor instances
Error message
Composition visuals belong to different compositor instances
What it means
ElementComposition.SetElementChildVisual attaches a custom CompositionVisual as the last child of a Visual's visual tree; it rejects the operation when the supplied visual's Compositor differs from the element's own composition visual's Compositor, because mixing visuals from different compositor instances breaks the single-render-loop invariant.
Source
Thrown at src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs:25
/// Enables access to composition visual objects that back XAML elements in the XAML composition tree.
/// </summary>
public static class ElementComposition
{
/// <summary>
/// Gets CompositionVisual that backs a Visual
/// </summary>
/// <param name="visual"></param>
/// <returns></returns>
public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual;
/// <summary>
/// Sets a custom <see cref="CompositionVisual"/> as the last child of the element’s visual tree.
/// </summary>
public static void SetElementChildVisual(Visual visual, CompositionVisual? compositionVisual)
{
if (compositionVisual != null && visual.CompositionVisual != null &&
compositionVisual.Compositor != visual.CompositionVisual.Compositor)
throw new InvalidOperationException("Composition visuals belong to different compositor instances");
visual.ChildCompositionVisual = compositionVisual;
visual.GetPresentationSource()?.Renderer.RecalculateChildren(visual);
}
/// <summary>
/// Retrieves a <see cref="CompositionVisual"/> object previously set by a call to <see cref="SetElementChildVisual" />.
/// </summary>
public static CompositionVisual? GetElementChildVisual(Visual visual) => visual.ChildCompositionVisual;
}
View on GitHub (pinned to 11c5427268)
Solutions
- Create the child CompositionVisual using the same Compositor as the host element (obtain via ElementComposition.GetElementVisual(host)?.Compositor or the element's renderer).
- Before attaching, assert childVisual.Compositor == hostVisual.CompositionVisual.Compositor.
- Do not cache and reuse CompositionVisuals across windows with distinct compositors.
Example fix
// before var child = otherCompositor.CreateSpriteVisual(); ElementComposition.SetElementChildVisual(host, child); // different compositor -> throws // after var compositor = ElementComposition.GetElementVisual(host)!.Compositor; var child = compositor.CreateSpriteVisual(); ElementComposition.SetElementChildVisual(host, child);
Defensive patterns
Strategy: validation
Validate before calling
var compositor = ElementComposition.GetElementVisual(host)?.Compositor;
if (compositionVisual != null && compositionVisual.Compositor != compositor)
throw new InvalidOperationException("child visual must use the host's compositor");
ElementComposition.SetElementChildVisual(host, compositionVisual); Type guard
static bool UsesSameCompositor(Visual host, CompositionVisual child) =>
host.CompositionVisual?.Compositor == child.Compositor; Prevention
- Create child visuals with the host element's Compositor.
- Do not reuse CompositionVisuals across windows with distinct compositors.
- Assert compositor equality before SetElementChildVisual.
When it happens
Trigger: Calling SetElementChildVisual(hostVisual, childVisual) where childVisual.Compositor != hostVisual.CompositionVisual.Compositor (e.g. the child was created via a Compositor from a different window).
Common situations: Creating a CompositionVisual on one window's Compositor and attaching it under a control hosted in another window; sharing composition visuals across surfaces with separate compositors.
Related errors
- This resource doesn't exist on that compositor
- {o.GetType()} belongs to a different compositor
- There is no server-side counterpart for this object
- The object doesn't have an associated server counterpart
- Transition elements have different parents.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/493456b7f92c6ba0.
Report an issue: GitHub.