{"record":{"id":"5b0c179dad541479","repo":"stride3d/stride","slug":"bound-render-targets-rendertargetcount-color-depth","errorCode":null,"errorMessage":"Bound render targets ({RenderTargetCount} color, depth: {depthStencilBuffer != null}) do not match the active pipeline's output ({output.RenderTargetCount} color, depth: {output.DepthStencilFormat != PixelFormat.None}). The render targets bound on the command list must match the pipeline's Output description.","messagePattern":"Bound render targets \\((.+?) color, depth: (.+?)\\) do not match the active pipeline's output \\((.+?) color, depth: (.+?)\\)\\. The render targets bound on the command list must match the pipeline's Output description\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs","lineNumber":1682,"sourceCode":"            // attachments and the depth layout stay the same\n            if (activeRendering && !renderingDirty && activeDepthReadOnly == depthReadOnly)\n                return;\n\n            // End old render pass instance\n            CleanupRenderPass();\n\n            var renderTarget = RenderTargetCount > 0 ? renderTargets[0] : depthStencilBuffer;\n            if (renderTarget == null)\n                return;\n\n            // An attachment mismatch with the pipeline's declared formats is undefined behavior that\n            // loses the device on strict drivers; fail loud in debug (only, to not break drivers that\n            // tolerate it) instead.\n            if (GraphicsDevice.IsDebugMode)\n            {\n                var output = activePipeline.Description.Output;\n                if (RenderTargetCount != output.RenderTargetCount || (depthStencilBuffer != null) != (output.DepthStencilFormat != PixelFormat.None))\n                    throw new InvalidOperationException(\n                        $\"Bound render targets ({RenderTargetCount} color, depth: {depthStencilBuffer != null}) do not match the active pipeline's output \" +\n                        $\"({output.RenderTargetCount} color, depth: {output.DepthStencilFormat != PixelFormat.None}). The render targets bound on the command list must match the pipeline's Output description.\");\n            }\n\n            // Clear attachments if needed\n            for (int index = 0; index < RenderTargetCount; index++)\n            {\n                if (!renderTarget.IsInitialized)\n                {\n                    Clear(renderTargets[index], Color.Transparent);\n                }\n            }\n\n            if (depthStencilBuffer != null && !depthStencilBuffer.IsInitialized)\n            {\n                Clear(depthStencilBuffer, DepthStencilClearOptions.DepthBuffer | DepthStencilClearOptions.Stencil);\n            }\n","sourceCodeStart":1664,"sourceCodeEnd":1700,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Vulkan/CommandList.Vulkan.cs#L1664-L1700","documentation":"In debug mode, Stride validates that the render targets bound on the command list match the active pipeline's Output description (number of color targets and presence of a depth-stencil). Mismatches are undefined behavior on strict Vulkan drivers, so Stride fails loudly with a detailed message.","triggerScenarios":"Setting a pipeline compiled for N color targets (with/without depth) while SetRenderTargets bound a different count or depth buffer, then executing a draw inside command list execution on Vulkan.","commonSituations":"Reusing a pipeline (effect/pass) with a framebuffer configured differently; binding depth buffer when the pipeline output has DepthStencilFormat None or vice versa; MRT pipelines applied to single-target framebuffers.","solutions":["Recreate the pipeline state with an Output description matching the currently bound render targets","Adjust SetRenderTargets to bind exactly the number of color targets and depth buffer the pipeline's Output declares","Verify EffectPass/PipelineState selection matches the current framebuffer layout"],"exampleFix":"// before\nvar pipeline = PipelineState.New(..., new RenderOutputDescription(2, PixelFormat.R8G8B8A8_UNorm));\nSetRenderTargetCount(1) // mismatch\n// after\nvar pipeline = PipelineState.New(..., new RenderOutputDescription(1, PixelFormat.R8G8B8A8_UNorm, PixelFormat.D32_Float));","handlingStrategy":"validation","validationCode":"var out0 = pipelineState.Description.Output;\nif (cmdList.RenderTargetCount != out0.RenderTargetCount) throw new InvalidOperationException(\"Bind render targets matching pipeline Output\");","typeGuard":null,"tryCatchPattern":"try { cmdList.Draw(...); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"Bound render targets\")) { /* rebind correct targets or select matching pipeline */ }","preventionTips":["Derive PipelineState Output from the exact framebuffer/rendertarget layout in use","Use EffectPass/PipelineState caches keyed by RenderOutputDescription","Enable debug mode in development to catch mismatches early"],"tags":["vulkan","pipeline-state","render-targets","debug-mode"],"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"}