dotnet/maui · warning · InvalidOperationException

IsHeadless cannot be modified when the view is rendered

Error message

IsHeadless cannot be modified when the view is rendered

What it means

Thrown by CompressedLayout.OnIsHeadlessPropertyChanged when IsHeadless is changed after the view has already been rendered (IsPlatformEnabled is true). IsHeadless controls layout compression — when true, the layout skips creating a platform view for the element. Changing this after the platform view exists would leave the view in an inconsistent state, so the property change is rejected. Note: the entire CompressedLayout API is marked Obsolete as it provides no meaningful functionality in MAUI.

Source

Thrown at src/Controls/src/Core/CompressedLayout.cs:39

		/// <returns><see langword="true" /> if layout compression is enabled for <paramref name="bindable" />. Otherwise, returns <see langword="false" />.</returns>
		[Obsolete("CompressedLayout does not provide meaningful functionality and may be removed in a future release. Please remove usage of this API.")]
		public static bool GetIsHeadless(BindableObject bindable)
			=> (bool)bindable.GetValue(IsHeadlessProperty);

		/// <summary>Turns layout compression on or off for the specified bindable object.</summary>
		/// <param name="bindable">The <see cref="BindableObject" /> on which to enable or disable layout compression</param>
		/// <param name="value">The new layout compression value. <see langword="true" /> to enable layout compression</param>
		[Obsolete("CompressedLayout does not provide meaningful functionality and may be removed in a future release. Please remove usage of this API.")]
		public static void SetIsHeadless(BindableObject bindable, bool value)
			=> bindable.SetValue(IsHeadlessProperty, BooleanBoxes.Box(value));

		static void OnIsHeadlessPropertyChanged(BindableObject bindable, object oldValue, object newValue)
		{
			var ve = bindable as IVisualElementController;
			if (ve == null)
				return;
			if (ve.IsPlatformEnabled)
				throw new InvalidOperationException("IsHeadless cannot be modified when the view is rendered");
		}

		static readonly BindablePropertyKey HeadlessOffsetPropertyKey =
			BindableProperty.CreateReadOnly("HeadlessOffset", typeof(Point), typeof(CompressedLayout), default(Point));

		/// <summary>Bindable property for <c>HeadlessOffset</c>.</summary>
		[EditorBrowsable(EditorBrowsableState.Never)]
		[Obsolete("CompressedLayout does not provide meaningful functionality and may be removed in a future release. Please remove usage of this API.")]
		public static readonly BindableProperty HeadlessOffsetProperty = HeadlessOffsetPropertyKey.BindableProperty;

		/// <summary>For internal use by the Microsoft.Maui.Controls platform.</summary>
		/// <param name="bindable">For internal use by the Microsoft.Maui.Controls platform.</param>
		/// <returns>For internal use by the Microsoft.Maui.Controls platform.</returns>
		[EditorBrowsable(EditorBrowsableState.Never)]
		[Obsolete("CompressedLayout does not provide meaningful functionality and may be removed in a future release. Please remove usage of this API.")]
		public static Point GetHeadlessOffset(BindableObject bindable)
			=> (Point)bindable.GetValue(HeadlessOffsetProperty);

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Set CompressedLayout.SetIsHeadless before the view is rendered — ideally in the constructor or XAML, before the page appears.
  2. Best option: remove CompressedLayout usage entirely since the API is marked Obsolete and provides no meaningful functionality in MAUI.
  3. If compression-like behavior is needed, use alternative approaches (e.g., IsVisible, layout optimization) instead of the deprecated API.
  4. Never call SetIsHeadless in lifecycle methods that fire after rendering (OnAppearing, OnSizeAllocated, event handlers).

Example fix

// before
public MyPage()
{
    InitializeComponent();
}
protected override void OnAppearing()
{
    base.OnAppearing();
    CompressedLayout.SetIsHeadless(myStackLayout, true); // throws — view is rendered
}

// after — set before render, or remove usage entirely
public MyPage()
{
    InitializeComponent();
    CompressedLayout.SetIsHeadless(myStackLayout, true); // before render — OK
}

// BEST: remove obsolete API entirely (it has no effect in MAUI)
// Simply delete the SetIsHeadless call.
Defensive patterns

Strategy: validation

Validate before calling

// Check IsPlatformEnabled before setting IsHeadless
if ((view as IVisualElementController)?.IsPlatformEnabled == true)
    return; // too late — skip or log warning
CompressedLayout.SetIsHeadless(view, value);

Type guard

public static bool CanSetIsHeadless(VisualElement view)
    => view != null && !((IVisualElementController)view).IsPlatformEnabled;

Prevention

When it happens

Trigger: At line 39: `if (ve.IsPlatformEnabled) throw new InvalidOperationException("IsHeadless cannot be modified when the view is rendered")`. The property changed callback fires when SetIsHeadless is called. If the target BindableObject is a VisualElement that has already been rendered (IsPlatformEnabled == true), the throw prevents toggling compression post-render. Triggered by calling CompressedLayout.SetIsHeadless on a view that is already displayed.

Common situations: 1) Calling CompressedLayout.SetIsHeadless(view, true) in a page lifecycle method after the page is already shown (e.g., OnAppearing). 2) Dynamically toggling compression on a view that's part of a rendered layout. 3) Code ported from Xamarin.Forms where IsHeadless was set at different lifecycle stages. 4) Setting IsHeadless in a binding/value converter that evaluates after render. 5) Not realizing the API is obsolete and attempting runtime changes.

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/c542dd41e21ef8e5. Report an issue: GitHub.