stride3d/stride · error · InvalidOperationException

InterfaceProcessor: If a

Error message

InterfaceProcessor: If a {entry.Stage} shader is specified, a vertex shader is needed too

What it means

While iterating the active shader stages after a non-vertex stage (HS/DS/GS), InterfaceProcessor.Process requires that a vertex shader entry point exists; tessellation and geometry stages consume vertex-stage output streams, so without VSMain the stream propagation model is incomplete and it throws.

Solutions

  1. Include a vertex shader mixin (exposing VSMain) in the composed ShaderSource
  2. Verify the composition/base-class chain did not override out the vertex stage class
  3. If the tessellation/geometry stage is intended standalone, compile it through a path that does not run InterfaceProcessor.Process

Example fix

// before
var shader = new ShaderSource(typeof(MyHullShader)).Compose(typeof(MyDomainShader));
// after
var shader = new ShaderSource(typeof(MyVertexShader)).Compose(typeof(MyHullShader)).Compose(typeof(MyDomainShader));
Defensive patterns

Strategy: validation

Validate before calling

bool hasTessOrGeometry = composition.Classes.Any(c => c.GetMethods().Any(m => m.Name is "HSMain" or "DSMain" or "GSMain"));
bool hasVertex = composition.Classes.Any(c => c.GetMethods().Any(m => m.Name == "VSMain"));
if (hasTessOrGeometry && !hasVertex)
    throw new InvalidOperationException("Tessellation/geometry stages require a vertex shader (VSMain) in the composition.");

Try / catch

try
{
    mixer.MergeSDSL(shaderSource, options, log, out var bytecode, out _, out _, out _);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("a vertex shader is needed too"))
{
    log.Error($"Missing vertex stage in composition: {ex.Message}");
}

Prevention

When it happens

Trigger: MergeSDSL on a module containing HSMain, DSMain, or GSMain entry points but no VSMain entry point — after processing that stage the code hits entryPointVS == null.

Common situations: Composing a hull/domain or geometry shader without including the vertex shader class; a mixin chain where the vertex stage class was excluded by composition overrides; compiling a tessellation-only test effect.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/InterfaceProcessor.cs:310

                                            !stream.Value.Patch && dsEntryPoint.ArrayInputSize is { } arrayInputSize ? new ArrayType(variableType, arrayInputSize) : variableType,
                                            Specification.StorageClass.Input);
                                        context.Add(new OpVariable(context.GetOrRegister(inputPointerType), dummyInputId, Specification.StorageClass.Input, null));
                                        context.Add(new OpDecorate(dummyInputId, Decoration.Location, [location]));
                                        if (variableType is ScalarType or VectorType or MatrixType && !variableType.GetElementType().IsFloating())
                                            context.Add(new OpDecorate(dummyInputId, Decoration.Flat, []));
                                        dsEntryPoint.InterfaceVariables.Add(dummyInputId);
                                    }
                                }
                            }
                        }

                        // Reset cbuffer/resource/methods used for next stage
                        DeadCodeRemover.ResetUsedThisStage(analysisResult, liveAnalysis);

                        VariableMerger.PropagateStreamsFromPreviousStage(streams);

                        if (entryPointVS == null)
                            throw new InvalidOperationException($"{nameof(InterfaceProcessor)}: If a {entry.Stage} shader is specified, a vertex shader is needed too");
                    }
                }

                if (entryPointVS != null)
                {
                    ReadWriteAnalyzer.AnalyzeStreamReadWrites(buffer, context, entryPointVS.IdRef, analysisResult, liveAnalysis);

                    // If specific semantic are written to (i.e. SV_Position), they are expected at the end of vertex shader
                    foreach (var stream in streams)
                    {
                        if (stream.Value.Semantic is { } semantic)
                        {
                            if (semantic.ToUpperInvariant().StartsWith("SV_POSITION") && requirePosition)
                            {
                                stream.Value.Output = true;
                                requirePosition = false;
                            }
                        }

View on GitHub (pinned to 96fad776d2)