stride3d/stride · error · ArgumentException

Invalid shader stage

Error message

Invalid shader stage

What it means

CommandList.SetUnorderedAccessView only accepts Unordered Access View binds on the Compute or Pixel shader stages. The guard at the top of the method rejects any other ShaderStage value with an ArgumentException naming the 'stage' parameter. It exists because D3D11 does not expose UAV binding points for the other shader stages.

Solutions

  1. Pass only ShaderStage.Compute or ShaderStage.Pixel when binding UAVs; skip other stages in your binding loop.
  2. If the resource must be visible to vertex/geometry stages, bind it as an SRV (SetShaderResourceView) instead of a UAV.
  3. Guard the call site with an explicit stage check and route or log unsupported stages rather than calling the API.

Example fix

// before
foreach (ShaderStage stage in Enum.GetValues<ShaderStage>())
    commandList.SetUnorderedAccessView(stage, 0, uavBuffer, -1);
// after
if (stage is ShaderStage.Compute or ShaderStage.Pixel)
    commandList.SetUnorderedAccessView(stage, 0, uavBuffer, -1);
Defensive patterns

Strategy: validation

Validate before calling

if (stage is not ShaderStage.Compute and not ShaderStage.Pixel)
    throw new InvalidOperationException($"UAV bind requires Compute or Pixel stage, got {stage}");
commandList.SetUnorderedAccessView(stage, slot, uavResource, -1);

Type guard

static bool SupportsUav(ShaderStage stage) => stage is ShaderStage.Compute or ShaderStage.Pixel;

Try / catch

try { commandList.SetUnorderedAccessView(stage, slot, uav, -1); }
catch (ArgumentException ex) when (ex.ParamName == "stage") { /* skip bind or log unsupported stage */ }

Prevention

When it happens

Trigger: Calling SetUnorderedAccessView (directly or via BindResources) with a stage such as ShaderStage.Vertex, Geometry, Domain, or Hull instead of ShaderStage.Compute or ShaderStage.Pixel.

Common situations: Mapping a resource-binding loop over all ShaderStage enum values and hitting non-UAV stages; porting Vulkan/GL code that permits UAV-like storage binds at more stages; a typo or off-by-one stage selection in a custom renderer built on Stride's Graphics layer.

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/5e9e35d83e949844. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D11/CommandList.Direct3D11.cs:486

        /// <param name="uavInitialOffset">
        ///   The Append/Consume Buffer offset.
        ///   <list type="bullet">
        ///     <item>A value of <c>-1</c> indicates the current offset should be kept.</item>
        ///     <item>
        ///       Any other value sets the hidden counter for that Appendable/Consumable UAV.
        ///       flag, otherwise the argument is ignored.
        ///     </item>
        ///   </list>
        ///   This parameter is only relevant for UAVs which have the <see cref="BufferFlags.StructuredAppendBuffer"/> or
        ///   <see cref="BufferFlags.StructuredCounterBuffer"/> Buffer flags.
        /// </param>
        /// <exception cref="ArgumentException">
        ///   Invalid <paramref name="stage"/>. Only valid options are <see cref="ShaderStage.Compute"/> and <see cref="ShaderStage.Pixel"/>.
        /// </exception>
        internal void SetUnorderedAccessView(ShaderStage stage, int slot, GraphicsResource unorderedAccessView, int uavInitialOffset)
        {
            if (stage is not ShaderStage.Compute and not ShaderStage.Pixel)
                throw new ArgumentException("Invalid shader stage", nameof(stage));

            var nativeUnorderedAccessView = unorderedAccessView is not null ? unorderedAccessView.NativeUnorderedAccessView : default;

            if (stage == ShaderStage.Compute)
            {
                if (unorderedAccessViews[slot].Handle != nativeUnorderedAccessView.Handle)
                {
                    unorderedAccessViews[slot] = nativeUnorderedAccessView;

                    nativeDeviceContext->CSSetUnorderedAccessViews((uint) slot, NumUAVs: 1, ref nativeUnorderedAccessView, (uint*) &uavInitialOffset);
                }
            }
            else // stage == ShaderStage.Pixel
            {
                if (currentUARenderTargetViews[slot].Handle != nativeUnorderedAccessView.Handle)
                {
                    OMSetSingleUnorderedAccessView(slot, nativeUnorderedAccessView, uavInitialOffset);
                }

View on GitHub (pinned to 96fad776d2)