stride3d/stride · error · InvalidOperationException
Use of undeclared stream variable
Error message
Use of undeclared stream variable '{streamVar.Name}' What it means
When a stream pointer is indexed with an identifier (e.g. stream var access during type processing, compiler == null), the compiler lets the identifier resolve stream variables. If after ProcessSymbol the identifier's type is not a PointerType, the symbol wasn't a declared stream variable, so this error is thrown. It indicates a reference to a name that is not a known stream in the stream-access chain.
Solutions
- Check spelling of the stream variable name against the declared streams in the shader signature.
- Ensure the stream variable is declared (as a stream/in/out with StreamsType) before it is accessed.
- Verify you are in a geometry-stream stage context where stream variables are valid.
Example fix
// before ouputStream.Append(v); // typo, undeclared // after outputStream.Append(v); // matches the declared stream variable
Defensive patterns
Strategy: validation
Validate before calling
// check the identifier refers to a declared stream before accessing
var sym = table.TryLookup(streamName);
if (sym?.Type is not PointerType)
throw new InvalidOperationException($"'{streamName}' is not a declared stream variable"); Type guard
static bool IsStreamVariable(Symbol s) => s?.Type is PointerType { BaseType: StreamsType }; Try / catch
try { CompileShader(source); }
catch (InvalidOperationException e) when (e.Message.StartsWith("Use of undeclared stream variable"))
{
// fix the stream name or declare the stream
} Prevention
- Verify stream variable names against the shader signature before use.
- Declare streams before any access in the shader body.
- Only reference stream variables inside stages that support stream access (e.g. geometry).
When it happens
Trigger: Indexing a StreamsType pointer with an Identifier whose ProcessSymbol resolution yields a non-pointer type — i.e. the name does not refer to a declared stream variable.
Common situations: Typos in stream variable names inside geometry shader stream-access expressions, referring to a stream before its declaration, or accessing a stream from a stage/effect where it was never declared as a stream.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- StreamOutput.Append() only accepts Streams or Output objects
- ParameterKey type [ ] is not supported by SetStream
- StreamType [ ] is not supported
- Struct not found in shader
- Could not find compositions for expression
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/45338da2b855352f.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Parsing/SDSL/AST/Expression.cs:1129
}
var (builder, context) = compiler;
var importedVariable = ShaderDefinition.ImportSymbol(table, context, field.ResolvedSymbol!);
// Emit OpAccessChain with everything so far
EmitOpAccessChain(accessChainIds, i - 1);
// TODO: figure out instance (this vs composition)
result = IdentifierBase.EmitSymbol(builder, context, importedVariable, false, result.Id);
break;
}
case (PointerType { BaseType: StreamsType s } p, Identifier streamVar):
if (compiler == null)
{
streamVar.AllowStreamVariables = true;
streamVar.ProcessSymbol(table);
if (streamVar.Type is not PointerType)
throw new InvalidOperationException($"Use of undeclared stream variable '{streamVar.Name}'");
accessor.Type = (PointerType)streamVar.Type with { StorageClass = p.StorageClass };
break;
}
// We emit chain access so far
// It's not necessary for SPIR-V, but StreamAccessPatcher.PatchStreamsAccesses() expect a simple format without
// multiple access chained (which make it harder to compute type)
EmitOpAccessChain(accessChainIds, i - 1);
// Since we cheated a bit by overwriting the accessor.Type, set it back during Compile()
accessor.Type = (PointerType)accessor.Type! with { StorageClass = Specification.StorageClass.Private };
// Since STREAMS struct is built later for each shader, we simply make a reference to variable for now
var streamVariableResult = streamVar.Compile(table, compiler);
accessor.Type = (PointerType)accessor.Type! with { StorageClass = p.StorageClass };
PushAccessChainId(accessChainIds, streamVariableResult.Id);
// For same reason as before (we want easy to detect pattern for StreamAccessPatcher), emit again
currentValueType = accessor.Type!;View on GitHub (pinned to 96fad776d2)