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

  1. Create the child CompositionVisual using the same Compositor as the host element (obtain via ElementComposition.GetElementVisual(host)?.Compositor or the element's renderer).
  2. Before attaching, assert childVisual.Compositor == hostVisual.CompositionVisual.Compositor.
  3. 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

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


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