{"record":{"id":"77e32d511163f549","repo":"stride3d/stride","slug":"cannot-create-a-swapchain-vulkan-surface-extensions-are-not","errorCode":null,"errorMessage":"Cannot create a swapchain: Vulkan surface extensions are not available. This may happen when using a headless ICD.","messagePattern":"Cannot create a swapchain: Vulkan surface extensions are not available\\. This may happen when using a headless ICD\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Vulkan/SwapChainGraphicsPresenter.Vulkan.cs","lineNumber":557,"sourceCode":"            if (surface != VkSurfaceKHR.Null)\n            {\n                GraphicsDevice.NativeInstanceApi.vkDestroySurfaceKHR(GraphicsDevice.NativeInstance, surface, null);\n                surface = VkSurfaceKHR.Null;\n            }\n            CreateSurface();\n        }\n\n        private unsafe void CreateSurface()\n        {\n            // Check for Window Handle parameter\n            if (Description.DeviceWindowHandle == null)\n            {\n                throw new ArgumentException(\"DeviceWindowHandle cannot be null\");\n            }\n\n            // Validate surface extension support (not available with headless ICDs)\n            if (!GraphicsAdapterFactory.GetInstance(GraphicsDevice.IsDebugMode).HasSurfaceSupport)\n                throw new InvalidOperationException(\"Cannot create a swapchain: Vulkan surface extensions are not available. This may happen when using a headless ICD.\");\n\n            // Create surface\n#if STRIDE_UI_SDL\n            // iOS reuses the SDL surface-creation path (GameContextiOS inherits GameContextSDL);\n            // SDL's VulkanCreateSurface routes to VkMetalSurfaceCreateInfoEXT internally on iOS.\n            if (Description.DeviceWindowHandle.Context == Games.AppContextType.DesktopSDL\n                || Description.DeviceWindowHandle.Context == Games.AppContextType.iOS)\n            {\n                var control = Description.DeviceWindowHandle.NativeWindow as SDL.Window;\n                Silk.NET.Core.Native.VkNonDispatchableHandle surfaceHandle = default;\n                SDL.Window.SDL.VulkanCreateSurface((Silk.NET.SDL.Window*)control.SdlHandle, new Silk.NET.Core.Native.VkHandle(GraphicsDevice.NativeInstance.Handle), ref surfaceHandle);\n                surface = new VkSurfaceKHR(surfaceHandle.Handle);\n            }\n            else\n#endif\n            if (Platform.Type == PlatformType.Windows)\n            {\n                var controlHandle = Description.DeviceWindowHandle.Handle;","sourceCodeStart":539,"sourceCodeEnd":575,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Vulkan/SwapChainGraphicsPresenter.Vulkan.cs#L539-L575","documentation":"Before creating a VkSurfaceKHR, CreateSurface checks that the Vulkan instance was created with the required surface extensions (VK_KHR_surface plus platform ones) via GraphicsAdapterFactory.GetInstance(...).HasSurfaceSupport. If the instance lacks surface support — typical of headless ICDs or compute-only environments — it throws InvalidOperationException because no swapchain can be presented.","triggerScenarios":"SwapChainGraphicsPresenter creation/recreation on a Vulkan instance without VK_KHR_*_surface extensions enabled, i.e. when HasSurfaceSupport is false (headless ICD, no display server, WSL without GPU surface support).","commonSituations":"Running in CI/containers with software Vulkan (lavapipe/headless ICD); SSH sessions without DISPLAY/WAYLAND_DISPLAY; WSL2 without WSLg; installing only compute drivers (e.g. NVIDIA compute-only driver) on servers.","solutions":["Install full graphics drivers and a display server (X11/Wayland) so the Vulkan loader exposes surface extensions.","On WSL2, enable WSLg or run the app natively on Windows with D3D backend.","Use the D3D11/D3D12 backend on Windows instead of Vulkan when only compute/headless Vulkan is available.","For CI/offscreen rendering, avoid swapchain creation and render to offscreen textures instead."],"exampleFix":"// before (container without display)\ndotnet StrideApp.dll\n// after: enable GPU + surface support\ndocker run --gpus all -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix ...","handlingStrategy":"validation","validationCode":"if (!GraphicsAdapterFactory.GetInstance(debug).HasSurfaceSupport)\n    throw new InvalidOperationException(\"Vulkan instance lacks surface extensions; cannot present\");","typeGuard":"bool CanPresent(GraphicsAdapterFactory f) => f.GetInstance(isDebug: false).HasSurfaceSupport;","tryCatchPattern":"try { presenter = new SwapChainGraphicsPresenter(device, desc); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"headless ICD\")) { log.Warn(\"No Vulkan surface support; falling back to D3D11 or offscreen rendering\"); SwitchToAlternativeBackend(); }","preventionTips":["Verify DISPLAY/WAYLAND_DISPLAY are set before launching on Linux","In containers/CI, use GPU passthrough with full driver stacks or avoid swapchains","On WSL2 enable WSLg or use the D3D backend","Check instance surface extension availability during app startup and pick backend accordingly"],"tags":["vulkan","surface","headless","swapchain"],"backgroundTag":"missing-dependency","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}