AvaloniaUI/Avalonia · critical · InvalidOperationException
SurfaceView.Holder was not expected to be null during Invali
Error message
SurfaceView.Holder was not expected to be null during InvalidationAwareSurfaceView initialization.
What it means
Thrown by the InvalidationAwareSurfaceView base constructor when the inherited SurfaceView.Holder is null at construction time. Per the Android framework, SurfaceView.getHolder() should never be null after super(context) completes, so this guard exists to fail fast on a broken/edge-case Context or a non-standard construction path.
Source
Thrown at src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs:32
internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback2, INativePlatformHandleSurface
{
private IntPtr _nativeWindowHandle = IntPtr.Zero;
private PixelSize _size = new(1, 1);
private double _scaling = 1;
public event EventHandler? SurfaceWindowCreated;
public event EventHandler? SurfaceWindowDestroyed;
public PixelSize Size => _size;
public double Scaling => _scaling;
IntPtr IPlatformHandle.Handle => _nativeWindowHandle;
string IPlatformHandle.HandleDescriptor => "SurfaceView";
protected InvalidationAwareSurfaceView(Context context) : base(context)
{
if (Holder is null)
throw new InvalidOperationException(
"SurfaceView.Holder was not expected to be null during InvalidationAwareSurfaceView initialization.");
Holder.AddCallback(this);
Holder.SetFormat(global::Android.Graphics.Format.Transparent);
}
protected override void Dispose(bool disposing)
{
if (disposing)
Holder?.RemoveCallback(this);
ReleaseNativeWindowHandle();
base.Dispose(disposing);
}
public virtual void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?View on GitHub (pinned to 11c5427268)
Solutions
- Always construct InvalidationAwareSurfaceView subclasses with a real, fully functional Context (the host Activity or a ContextThemeWrapper over it).
- In tests, use a Robolectric or instrumentation runner that provides a working view infrastructure rather than a bare mock Context.
- Verify the AndroidX fragment/appcompat libraries are at supported versions; a mismatch can alter View initialization ordering.
- Do not bypass the base SurfaceView lifecycle — let super(context) run normally before any custom init.
Example fix
// before — context is a stripped mock var view = new SurfaceViewImpl(mockContext, topLevel, false); // after — use the real activity context var view = new SurfaceViewImpl(activityContext, topLevel, false);
Defensive patterns
Strategy: validation
Validate before calling
// ensure a real, fully functional Context is passed before constructing the view
if (context is null || !IsRealContext(context))
throw new InvalidOperationException("A real Activity context is required.");
var view = new SurfaceViewImpl(context, topLevel, placeOnTop); Type guard
static bool IsRealContext(Context? c) => c is Android.App.Activity or ContextWrapper;
Prevention
- Always construct surface views with the host Activity (or a ContextThemeWrapper over it).
- In tests, use Robolectric/instrumentation context, not a bare mock.
- Keep AndroidX/fragment library versions consistent to preserve View init ordering.
- Do not subclass-constrain the SurfaceView base constructor.
When it happens
Trigger: Constructing an InvalidationAwareSurfaceView subclass with a Context that does not properly initialize the View infrastructure, or constructing it before the framework attaches a window. Most realistically hit by instantiating the view with an invalid Context (e.g. a stripped/mock context, or during unit tests without a real Android view stack).
Common situations: Running instrumentation/unit tests that construct the view with a mock Context; passing a ContextWrapper that delegates incorrectly; using the view in a non-standard host (e.g. Flutter plugin interop) where the SurfaceView base behavior is overridden; AndroidX/fragment framework version mismatches that alter Holder initialization timing.
Related errors
- Unable to obtain ANativeWindow
- AvaloniaView.Context must not be null
- Surface handle can't be 0x0
- The control isn't currently attached to a toplevel
- Context.InputMethodService is expected to be not null.
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/d6e879ef2e23d834.
Report an issue: GitHub.