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
- Include a vertex shader mixin (exposing VSMain) in the composed ShaderSource
- Verify the composition/base-class chain did not override out the vertex stage class
- 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
- Compose full pipelines (VS + optional HS/DS/GS + PS) rather than isolated stages
- Check that base-class overrides do not silently drop the vertex stage class
- Add pipeline-level compile tests covering tessellation/geometry effects
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
- InterfaceProcessor: At least a pixel or compute shader is…
- Can't cast from to (larger matrix)
- Can't cast from to
- Can't cast from to
- Can't figure array output size for tessellation shader
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)