stride3d/stride · error · NotSupportedException

Unsupported shader stage

Error message

Unsupported shader stage: {shaderStage}

What it means

On desktop targets, EffectCompiler derives an HLSL file suffix (vs/hs/ds/gs/ps/cs) from the resolved ShaderStage to feed FXC/DXC. A ShaderStage value outside that set hits the switch default and throws NotSupportedException. This is an internal completeness check after the execution-model mapping, so it fires only when an unmapped stage value flows into HLSL source generation.

Solutions

  1. Ensure each compiled entry point maps to exactly one supported ShaderStage (Vertex, Hull, Domain, Geometry, Pixel, Compute).
  2. Do not pass combined or custom ShaderStage flags into EffectCompiler; compile one entry point per stage.
  3. Update Stride so the execution-model-to-stage and stage-to-suffix switches are from the same version.
  4. If adding a new stage, extend both switch expressions in EffectCompiler.cs (ShaderStage mapping and stageSuffix mapping).

Example fix

// before: combined flag reaches the suffix switch
var stage = ShaderStage.Vertex | ShaderStage.Pixel; // falls through -> throws

// after: one stage per entry point
foreach (var stage in entryStages) // exactly one of vs/hs/ds/gs/ps/cs per compile
    CompileStage(stage);
Defensive patterns

Strategy: validation

Validate before calling

// verify each stage is a single, supported ShaderStage before compiling
private static readonly HashSet<ShaderStage> HlslStages = new()
    { ShaderStage.Vertex, ShaderStage.Hull, ShaderStage.Domain, ShaderStage.Geometry, ShaderStage.Pixel, ShaderStage.Compute };

if (entryStages.Any(s => !HlslStages.Contains(s)))
    throw new InvalidOperationException("Each compiled entry point must resolve to exactly one of vs/hs/ds/gs/ps/cs stages.");

Type guard

static bool IsSingleHlslStage(ShaderStage stage) =>
    stage is ShaderStage.Vertex or ShaderStage.Hull or ShaderStage.Domain
        or ShaderStage.Geometry or ShaderStage.Pixel or ShaderStage.Compute;

Try / catch

try
{
    var effect = effectCompiler.Compile(effectSource, parameters);
}
catch (NotSupportedException ex) when (ex.Message.StartsWith("Unsupported shader stage"))
{
    log.Error($"Stage cannot be mapped to an HLSL suffix: {ex.Message}. Compile one entry point per single stage.");
    throw;
}

Prevention

When it happens

Trigger: EffectCompiler.Compile on STRIDE_PLATFORM_DESKTOP resolves a shaderStage that is not one of {Vertex, Hull, Domain, Geometry, Pixel, Compute} when building stage HLSL sources — practically only reachable if stage translation produced/amplified a nonstandard stage (e.g. a combined or unknown stage flag from the preceding mapping step).

Common situations: Custom ShaderStage values introduced by downstream code or plugins; misuse of the compiler API passing raw stage flags; a merge of stage bits rather than a single stage; compiler/version skew between the stage mapper and the suffix mapper.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Compilers/EffectCompiler.cs:284

                            ExecutionModel.Vertex => ShaderStage.Vertex,
                            ExecutionModel.TessellationControl => ShaderStage.Hull,
                            ExecutionModel.TessellationEvaluation => ShaderStage.Domain,
                            ExecutionModel.Geometry => ShaderStage.Geometry,
                            ExecutionModel.Fragment => ShaderStage.Pixel,
                            ExecutionModel.GLCompute => ShaderStage.Compute,
                            _ => throw new NotSupportedException($"Unsupported execution model: {entryPoint.ExecutionModel}"),
                        };

#if STRIDE_PLATFORM_DESKTOP
                        var stageSuffix = shaderStage switch
                        {
                            ShaderStage.Vertex => "vs",
                            ShaderStage.Hull => "hs",
                            ShaderStage.Domain => "ds",
                            ShaderStage.Geometry => "gs",
                            ShaderStage.Pixel => "ps",
                            ShaderStage.Compute => "cs",
                            _ => throw new NotSupportedException($"Unsupported shader stage: {shaderStage}"),
                        };
                        stageHlslSources.Add((stageSuffix, code));
                        string? stageFilename = null;
#else
                        string? stageFilename = null;
#endif
                        var result = compiler!.Compile(code, entryPoint.TranslatedName, shaderStage, effectParameters, bytecode.Reflection, stageFilename);
                        result.CopyTo(log);

                        if (result.HasErrors)
                        {
                            continue;
                        }

                        // Guard against a silent null bytecode (actionable message instead of NRE below).
                        if (result.Bytecode is null)
                        {
                            log.Error($"Shader compilation for stage {shaderStage} (entry '{entryPoint.TranslatedName}') produced no bytecode and no error.");

View on GitHub (pinned to 96fad776d2)