stride3d/stride · error · ArgumentException

DeviceWindowHandle cannot be null

Error message

DeviceWindowHandle cannot be null

What it means

CreateSurface needs a target window handle to create the platform VkSurfaceKHR; if SwapChainGraphicsPresenter's Description.DeviceWindowHandle is null it throws ArgumentException. Without a window there is nothing to present to, and the non-headless code path cannot proceed.

Solutions

  1. Set Description.DeviceWindowHandle to a valid window (e.g. game.Window.NativeWindow or new WindowHandle(context, windowPtr)) before creating the presenter.
  2. Ensure the game window is created before graphics device/presenter initialization.
  3. For offscreen rendering, use the headless path instead of a swapchain presenter.

Example fix

// before
var presenter = new SwapChainGraphicsPresenter(device, new SwapChainDescription { ... });
// after
var desc = new SwapChainDescription { ... };
desc.DeviceWindowHandle = game.Window.Handle;
var presenter = new SwapChainGraphicsPresenter(device, desc);
Defensive patterns

Strategy: validation

Validate before calling

if (swapChainDescription.DeviceWindowHandle == null)
    throw new InvalidOperationException("Set DeviceWindowHandle before creating the SwapChainGraphicsPresenter");

Type guard

bool HasWindowHandle(SwapChainDescription d) => d.DeviceWindowHandle is not null;

Try / catch

try { presenter = new SwapChainGraphicsPresenter(device, desc); }
catch (ArgumentException ex) when (ex.Message.Contains("DeviceWindowHandle cannot be null")) { log.Error("No window handle configured for swapchain", ex); throw; }

Prevention

When it happens

Trigger: Constructing or recreating a SwapChainGraphicsPresenter with a SwapChainDescription whose DeviceWindowHandle was never set (null).

Common situations: Building a Game/graphics context programmatically and forgetting to assign Game.Window / DeviceWindowHandle; creating the presenter before the game window exists; copying a description struct that dropped the handle.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/e7334a9eb38eaec7. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Vulkan/SwapChainGraphicsPresenter.Vulkan.cs:552

        private unsafe void RecreateSurface()
        {
            // Swapchain must be torn down before the surface (Vulkan spec + Android ANativeWindow exclusivity).
            DestroySwapchain();
            if (surface != VkSurfaceKHR.Null)
            {
                GraphicsDevice.NativeInstanceApi.vkDestroySurfaceKHR(GraphicsDevice.NativeInstance, surface, null);
                surface = VkSurfaceKHR.Null;
            }
            CreateSurface();
        }

        private unsafe void CreateSurface()
        {
            // Check for Window Handle parameter
            if (Description.DeviceWindowHandle == null)
            {
                throw new ArgumentException("DeviceWindowHandle cannot be null");
            }

            // Validate surface extension support (not available with headless ICDs)
            if (!GraphicsAdapterFactory.GetInstance(GraphicsDevice.IsDebugMode).HasSurfaceSupport)
                throw new InvalidOperationException("Cannot create a swapchain: Vulkan surface extensions are not available. This may happen when using a headless ICD.");

            // Create surface
#if STRIDE_UI_SDL
            // iOS reuses the SDL surface-creation path (GameContextiOS inherits GameContextSDL);
            // SDL's VulkanCreateSurface routes to VkMetalSurfaceCreateInfoEXT internally on iOS.
            if (Description.DeviceWindowHandle.Context == Games.AppContextType.DesktopSDL
                || Description.DeviceWindowHandle.Context == Games.AppContextType.iOS)
            {
                var control = Description.DeviceWindowHandle.NativeWindow as SDL.Window;
                Silk.NET.Core.Native.VkNonDispatchableHandle surfaceHandle = default;
                SDL.Window.SDL.VulkanCreateSurface((Silk.NET.SDL.Window*)control.SdlHandle, new Silk.NET.Core.Native.VkHandle(GraphicsDevice.NativeInstance.Handle), ref surfaceHandle);
                surface = new VkSurfaceKHR(surfaceHandle.Handle);
            }

View on GitHub (pinned to 96fad776d2)