{"record":{"id":"5009ec10f7d76e7f","repo":"stride3d/stride","slug":"could-not-acquire-swapchain-image-result","errorCode":null,"errorMessage":"Could not acquire swapchain image: {result}","messagePattern":"Could not acquire swapchain image: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Vulkan/SwapChainGraphicsPresenter.Vulkan.cs","lineNumber":209,"sourceCode":"            // Wait for frame fence to be available\n            GraphicsDevice.CheckResult(GraphicsDevice.NativeDeviceApi.vkWaitForFences(GraphicsDevice.NativeDevice, frameFences[currentFrameIndex], VkBool32.True, ulong.MaxValue));\n            GraphicsDevice.NativeDeviceApi.vkResetFences(GraphicsDevice.NativeDevice, frameFences[currentFrameIndex]);\n\n            AcquireNextImage();\n        }\n\n        private unsafe void AcquireNextImage()\n        {\n            // Get next image\n            var result = GraphicsDevice.NativeDeviceApi.vkAcquireNextImageKHR(GraphicsDevice.NativeDevice, swapChain, ulong.MaxValue, acquireSemaphores[currentFrameIndex], VkFence.Null, out currentBufferIndex);\n            if (result == VkResult.ErrorOutOfDateKHR || result == VkResult.ErrorSurfaceLostKHR)\n            {\n                // No image acquired: the surface changed while the swapchain was being (re)created\n                // (continuous interactive resize) or was lost. Recreate against the current surface\n                // state; bounded, as each attempt re-queries the surface so it converges once the\n                // surface settles.\n                if (acquireRecreateDepth >= 3)\n                    throw new InvalidOperationException($\"Could not acquire swapchain image: {result}\");\n                acquireRecreateDepth++;\n                try { OnRecreated(); }\n                finally { acquireRecreateDepth--; }\n                return;\n            }\n\n            // SuboptimalKHR is a success code: an image was acquired and the semaphore will be\n            // signaled; the next Present reports it again and recreates the swapchain.\n            if (result != VkResult.SuboptimalKHR)\n            {\n                GraphicsDevice.CheckResult(result, \"vkAcquireNextImageKHR\");\n            }\n\n            // Flip render targets\n            backBuffer.SetNativeHandles(swapchainImages[currentBufferIndex].NativeImage, swapchainImages[currentBufferIndex].NativeColorAttachmentView);\n\n            lock (GraphicsDevice.QueueLock)\n            {","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Vulkan/SwapChainGraphicsPresenter.Vulkan.cs#L191-L227","documentation":"AcquireNextImage calls vkAcquireNextImageKHR and, when it can't get an image (e.g. VK_ERROR_OUT_OF_DATE_KHR), attempts up to 3 bounded recoveries by recreating the swapchain (OnRecreated). If the surface keeps changing or remains unusable after 3 attempts, it throws InvalidOperationException with the failing VkResult embedded, since continuing without a back-buffer image is impossible.","triggerScenarios":"Present() or CreateBackBuffers() calling AcquireNextImage while the window surface is continuously resized, minimized, or destroyed, so that vkAcquireNextImageKHR keeps returning out-of-date/error results through 3 recreation attempts.","commonSituations":"User dragging/resizing the window rapidly on Wayland/Windows; window minimized during Present; GPU reset or swapchain invalidation during heavy window management; running under compositors that force swapchain recreation per frame.","solutions":["Skip rendering/presenting while the window is minimized or has zero-size (check before Present).","Clamp back-buffer size to at least 1x1 and to current surface extent so recreation converges.","Update Vulkan drivers / compositor environment if recreation never converges.","Inspect the VkResult in the message (e.g. ERROR_OUT_OF_DATE_KHR vs ERROR_DEVICE_LOST) — device-lost requires device re-creation, not just swapchain recreation."],"exampleFix":"// before\nswapChain.Present();\n// after\nif (!gameWindow.Visible || gameWindow.ClientSize.Width == 0 || gameWindow.ClientSize.Height == 0) return;\nswapChain.Present();","handlingStrategy":"retry","validationCode":"bool CanPresent(GameWindow w) => w.Visible && w.ClientSize.Width > 0 && w.ClientSize.Height > 0;","typeGuard":"bool SurfaceUsable(IntPtr hwnd) => hwnd != IntPtr.Zero && IsWindowVisible(hwnd) && !IsIconic(hwnd);","tryCatchPattern":"try { swapChain.Present(); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"Could not acquire swapchain image\")) {\n    // surface never settled (minimized/zero-size): pause rendering until next frame\n    skipFramesUntilResizeEnds = true;\n}","preventionTips":["Skip Present while the window is minimized or has zero extent","Clamp back-buffer sizes to at least 1x1 and to the current surface capabilities","Handle resize events by pausing rendering, not by forcing immediate presents","Read the VkResult in the message to distinguish out-of-date (transient) from device-lost (fatal)"],"tags":["vulkan","swapchain","present","resize"],"backgroundTag":"invalid-state-transition","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"}