stride3d/stride · error · InvalidOperationException

Stream ' ' is expected as a vertex shader input and is…

Error message

Stream '{stream.Value.Name}'{readBy} is expected as a vertex shader input and is never written by any shader stage before being read. Without a semantic it cannot be sourced from a vertex buffer, so it has to be produced by a shader: write to streams.{stream.Value.Name} before reading it, or give it a semantic if it really is a vertex buffer input.

What it means

After stream analysis, InterfaceProcessor.Process builds the vertex input layout from streams read by the vertex shader. A stream that is a vertex-shader input with an input-layout location but no semantic cannot come from a vertex buffer, so it must be produced by an earlier stage; since no stage writes it before being read, the processor throws with the stream name and reading method.

Solutions

  1. Write to the stream before reading it, e.g. assign streams.MyValue at the top of VSMain or in an earlier stage
  2. Add a semantic (e.g. [Semantic("POSITION")] / SV semantics) to the stream member so it is treated as a vertex-buffer input
  3. Check the composition for the missing mixin that was supposed to produce this stream, or fix the stream-name typo

Example fix

// before
struct StreamsOutput { [Location(0)] float4 Value; } // no semantic, never written
public override void Main() { float4 v = streams.Value; }
// after
struct StreamsOutput { [Location(0)][Semantic("POSITION")] float4 Value; }
public override void Main() { streams.Value = float4(0,0,0,1); float4 v = streams.Value; }
Defensive patterns

Strategy: validation

Validate before calling

// Static review helper: every stream read in VSMain must be written or carry a semantic
foreach (var stream in vertexInputs)
{
    if (!stream.IsWrittenByAnyStage && string.IsNullOrEmpty(stream.Semantic))
        throw new InvalidOperationException($"Stream '{stream.Name}' has no semantic and no producer; add [Semantic(...)] or write to streams.{stream.Name} before reading.");
}

Try / catch

try
{
    mixer.MergeSDSL(shaderSource, options, log, out var bytecode, out _, out _, out _);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("expected as a vertex shader input"))
{
    log.Error("Unsourced vertex stream: " + ex.Message);
}

Prevention

When it happens

Trigger: MergeSDSL where the vertex entry point reads a streams.X member that (a) has no Semantic attached and (b) is never written by any earlier stage — e.g. a stream declared as input and read in VSMain without ever being assigned.

Common situations: Forgetting to assign a streams field in a previous stage or in the vertex shader itself; typo in the stream name so the write targets a different member; porting HLSL code where the semantic attribute was lost; a mixin expects another mixin to write the stream but is not composed in.

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/462d1a57bd1b3e52. Report an issue: GitHub.

Appendix: source

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

                            {
                                stream.Value.Output = true;
                                requirePosition = false;
                            }
                        }
                    }

                    entryPoints.Add(GenerateStreamWrapper(table, buffer, context, ExecutionModel.Vertex, entryPointVS, analysisResult, liveAnalysis, true));

                    // Process shader input attributes
                    foreach (var stream in streams)
                    {
                        // Note: built-ins won't have a inputLayoutLocation so they will be skipped
                        if (stream.Value.Input && stream.Value.InputLayoutLocation is { } inputLayoutLocation)
                        {
                            if (stream.Value.Semantic == null)
                            {
                                var readBy = stream.Value.ReadByMethod is { } m ? $" (read by '{m}')" : "";
                                throw new InvalidOperationException(
                                    $"Stream '{stream.Value.Name}'{readBy} is expected as a vertex shader input and is never written by any shader stage before being read. " +
                                    $"Without a semantic it cannot be sourced from a vertex buffer, so it has to be produced by a shader: " +
                                    $"write to streams.{stream.Value.Name} before reading it, or give it a semantic if it really is a vertex buffer input.");
                            }
                            var semantic = SemanticAnalyzer.ParseSemantic(stream.Value.Semantic);
                            inputAttributes.Add(new ShaderInputAttributeDescription { Location = inputLayoutLocation, SemanticName = semantic.Name, SemanticIndex = semantic.Index });
                        }
                    }
                }
            }

            // Emit all OpEntryPoints (deferred to allow fixups like adding dummy DS inputs for HS-internal outputs)
            foreach (var ep in entryPoints)
                context.Add(new OpEntryPoint(ep.Model, ep.Id, ep.Name, [.. ep.InterfaceVariables]));

            // Entry points had their geometry stream parameter removed as their wrapper was
            // generated; any other method carrying one has to lose it too.
            RemoveGeometryStreamParameters(buffer, context);

View on GitHub (pinned to 96fad776d2)