AvaloniaUI/Avalonia · critical · ArgumentException
Surface handle can't be 0x0
Error message
Surface handle can't be 0x0
What it means
Thrown by VulkanSupport.CreateAndroidSurface when the native surface handle passed in is IntPtr.Zero. VkCreateAndroidSurfaceKHR requires a valid ANativeWindow pointer; a zero handle means the window/surface was never created or was destroyed before the Vulkan surface could be built.
Source
Thrown at src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs:58
{
_handle = handle;
}
public double Scaling => _handle.Scaling;
public PixelSize Size => _handle.Size;
public ulong CreateSurface(IVulkanPlatformGraphicsContext context) =>
CreateAndroidSurface(_handle.Handle, context.Instance);
public void Dispose()
{
// No-op
}
}
private static ulong CreateAndroidSurface(nint handle, IVulkanInstance instance)
{
if(handle == IntPtr.Zero)
throw new ArgumentException("Surface handle can't be 0x0", nameof(handle));
var vulkanAndroid = new AndroidVulkanInterface(instance);
var createInfo = new VkAndroidSurfaceCreateInfoKHR()
{
sType = VkAndroidSurfaceCreateInfoKHR.VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
window = handle
};
VulkanException.ThrowOnError("vkCreateAndroidSurfaceKHR",
vulkanAndroid.vkCreateAndroidSurfaceKHR(instance.Handle, ref createInfo, IntPtr.Zero, out var surface));
return surface;
}
}
}
View on GitHub (pinned to 11c5427268)
Solutions
- Ensure the surface is created (SurfaceWindowCreated fired with a valid handle) before the Vulkan graphics context is initialized.
- Defer Vulkan surface creation until InvalidationAwareSurfaceView exposes a non-zero native window handle.
- On surface destroy, tear down the Vulkan swapchain/surface before the handle goes to zero.
- If Vulkan reliability is a concern, fall back to the Skia/Framebuffer backend via .With(new SkiaOptions()).
Example fix
// before
// vulkan context created eagerly in constructor, surface may be 0x0
graphicsContext = vulkanPlatform.CreateContext();
// after — wait for a valid surface handle
_surfaceView.SurfaceWindowCreated += (s, e) =>
{
if (((IPlatformHandle)_surfaceView).Handle != IntPtr.Zero)
graphicsContext = vulkanPlatform.CreateContext();
}; Defensive patterns
Strategy: validation
Validate before calling
// confirm the surface handle is valid before creating the Vulkan surface
if (((IPlatformHandle)surfaceView).Handle == IntPtr.Zero)
return; // surface not ready
var surface = vulkanPlatform.CreateSurface(context); Type guard
static bool HasValidSurfaceHandle(InvalidationAwareSurfaceView? v) => v is IPlatformHandle h && h.Handle != IntPtr.Zero;
Prevention
- Initialize the Vulkan context only after SurfaceWindowCreated yields a non-zero handle.
- Tear down Vulkan surfaces on SurfaceWindowDestroyed before the handle clears.
- Gate surface creation on a validated handle in custom embeds.
- Fall back to Skia/Framebuffer backend if Vulkan timing proves unreliable on target devices.
When it happens
Trigger: Calling CreateSurface(IVulkanPlatformGraphicsContext) when the context's surface handle (typically the InvalidationAwareSurfaceView's native window handle) is zero. Same root cause as the ANativeWindow framebuffer error: surface not yet created, already destroyed, or view detached.
Common situations: Selecting the Vulkan render backend while the surface is not ready; lifecycle race during pause/resume; embedding AvaloniaView detached from the window; using Vulkan on a device/config where the surface creation timing differs; combining Vulkan with a custom surface view that yields a zero handle.
Related errors
- Unable to obtain ANativeWindow
- AndroidPlatformOptions.RenderingMode must not be empty or nu
- AndroidPlatformOptions.RenderingMode has a value of "{opts.R
- TopLevel.InternalView was not expected to be null.
- SurfaceView.Holder was not expected to be null during Invali
AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13).
Data as JSON: /api/errors/b47fa9c610093ed4.
Report an issue: GitHub.