stride3d/stride · error · ArgumentOutOfRangeException

Invalid Shader stage specified in the Effect bytecode.

Error message

Invalid Shader stage specified in the Effect bytecode.

What it means

While building the D3D12 graphics pipeline state, each shader in the EffectBytecode is mapped to the corresponding pipeline slot (VS/HS/DS/GS/PS). If the bytecode contains a shader whose stage is not one of those (e.g. a Compute stage in a graphics pipeline, or an invalid value), the switch hits default and throws ArgumentOutOfRangeException for pipelineStateDescription.

Solutions

  1. Ensure graphics PipelineStateDescription uses only vertex/hull/domain/geometry/pixel shaders
  2. Create a separate ComputePipelineState (or compute path) for compute shaders
  3. Recompile/verify the effect bytecode and its ShaderStage metadata

Example fix

// before
var desc = new PipelineStateDescription { EffectBytecode = computeEffect.Bytecode, ... };
var state = PipelineState.New(graphicsDevice, desc);
// after
var desc = new PipelineStateDescription { EffectBytecode = graphicsEffect.Bytecode, ... };
var state = PipelineState.New(graphicsDevice, desc);
Defensive patterns

Strategy: validation

Validate before calling

if (bytecode.Stages.Any(s => s.Stage == ShaderStage.Compute)) throw new InvalidOperationException("Compute shader cannot be used in a graphics PipelineState");

Type guard

bool IsGraphicsStage(ShaderStage s) => s is ShaderStage.Vertex or ShaderStage.Hull or ShaderStage.Domain or ShaderStage.Geometry or ShaderStage.Pixel;

Try / catch

try { state = PipelineState.New(device, desc); } catch (ArgumentOutOfRangeException) { /* log invalid effect bytecode stage */ throw; }

Prevention

When it happens

Trigger: Passing a PipelineStateDescription whose EffectBytecode contains a shader with ShaderStage.Compute or an unhandled stage into the graphics PipelineState constructor; corrupted/incorrectly compiled effect bytecode with wrong stage metadata.

Common situations: Reusing a compute-effect bytecode to create a graphics pipeline state; migrating effects between backends where stage enums were serialized incorrectly; copy-paste errors building effect bytecode.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D12/PipelineState.Direct3D12.cs:255

                var rtvFormats = nativePipelineStateDescription.RTVFormats.AsSpan();
                Debug.Assert(sizeof(PixelFormat) == sizeof(Format));
                Debug.Assert(rtvFormats.Length == pipelineStateDescription.Output.RenderTargetFormats.Length);
                pipelineStateDescription.Output.RenderTargetFormats.As<PixelFormat, Format>().CopyTo(rtvFormats);

                foreach (var stage in pipelineStateDescription.EffectBytecode.Stages)
                {
                    var shaderBytecode = GetShaderBytecode(stage.Data);

                    switch (stage.Stage)
                    {
                        case ShaderStage.Vertex:   nativePipelineStateDescription.VS = shaderBytecode; break;
                        case ShaderStage.Hull:     nativePipelineStateDescription.HS = shaderBytecode; break;
                        case ShaderStage.Domain:   nativePipelineStateDescription.DS = shaderBytecode; break;
                        case ShaderStage.Geometry: nativePipelineStateDescription.GS = shaderBytecode; break;
                        case ShaderStage.Pixel:    nativePipelineStateDescription.PS = shaderBytecode; break;

                        default:
                            throw new ArgumentOutOfRangeException(nameof(pipelineStateDescription), "Invalid Shader stage specified in the Effect bytecode.");
                    }
                }

                result = NativeDevice.CreateGraphicsPipelineState(in nativePipelineStateDescription, out ComPtr<ID3D12PipelineState> pipelineState);

                if (result.IsFailure)
                    result.Throw();

                compiledPipelineState = pipelineState;
            }

            nativeRootSignature = rootSignature;
            PrimitiveTopology = (D3DPrimitiveTopology) pipelineStateDescription.PrimitiveType;
            HasScissorEnabled = pipelineStateDescription.RasterizerState.ScissorTestEnable;

            FreeAllTempMemoryAllocations();

            //

View on GitHub (pinned to 96fad776d2)