stride3d/stride · error · InvalidOperationException
OpAccessChain on PatchType/array-of-Streams can have only 1…
Error message
OpAccessChain on PatchType/array-of-Streams can have only 1 element
What it means
When AnalyzeStreamReadWrites encounters an access chain whose base is a patch variable or a geometry input array, it treats index [0] as the stream selector and only that single index is allowed. An OpAccessChain with more than one index on such a base throws InvalidOperationException.
Solutions
- Split the access: first index the patch/array element, then access members via separate access chains
- Index patches only with a single selector index as the analyzer expects
- Check your SDSL source for nested indexing on patch/geometry-input arrays and flatten it
- If generated by a transformation, fix the code generator to emit one access chain per level
Example fix
// before // OpAccessChain patch[0].member (2 indexes) // after var elem = patch[0]; var member = elem.member; // separate access chains
Defensive patterns
Strategy: validation
Validate before calling
if (accessChain.Indexes.Elements.Length > 1 && patchInstructionIds.ContainsKey(accessChain.Base))
throw new InvalidOperationException("Patch/array-of-streams access chain must use exactly 1 index"); Try / catch
try { analyzer.AnalyzeStreamReadWrites(module); } catch (InvalidOperationException ex) { logger.LogError(ex, "Bad access chain on patch/stream array"); throw; } Prevention
- Index patches with a single selector index in SDSL
- Decompose multi-level accesses into separate access chains in code generators
- Add IR validation between transformations that create access chains
When it happens
Trigger: An OpAccessChain on a patch or array-of-streams base carrying 2+ indexes — e.g. patch[i].member or input[i][j] — inside AnalyzeStreamReadWrites.
Common situations: Hull/domain shader code indexing into a patch array and then a member through the same access chain; generated code emitting multi-level access chains on stream arrays instead of decomposing them.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Can't write value on input or output struct
- Variable initializer is not supported on streams variable
- 64bit integers
- Can't add type
- Could not load shader
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/7dd4a65d647fcf18.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Processing/Interfaces/Analysis/ReadWriteAnalyzer.cs:192
if (analysisResult.Resources.TryGetValue(structureId, out var resourceInfo3))
resourceInfo3.UsedThisStage = true;
}
else if (i.Op == Op.OpStreamsSDSL && new OpStreamsSDSL(ref i) is { } streamsInstruction)
{
streamsInstructionIds.Add(streamsInstruction.ResultId, StreamsKindSDSL.Streams);
methodInfo.HasStreamAccess = true;
}
else if (i.Op == Op.OpAccessChain && new OpAccessChain(ref i) is { } accessChain)
{
var currentBase = accessChain.BaseId;
// In case it's a patch or geometry-input-array access, i.e. patch[0] or input[0],
// mark the access as being a stream
if (patchInstructionIds.TryGetValue(currentBase, out var patchStreamKind))
{
var patchVariableId = accessChain.Indexes.Elements.Span[0];
if (accessChain.Indexes.Elements.Length > 1)
throw new InvalidOperationException("OpAccessChain on PatchType/array-of-Streams can have only 1 element");
streamsInstructionIds.Add(accessChain.ResultId, patchStreamKind);
}
else
{
StreamsKindSDSL? currentStreamKind = null;
// In case it's a streams access, mark the stream as being the base
if (streamsInstructionIds.TryGetValue(currentBase, out var streamKind))
{
var streamVariableId = accessChain.Indexes.Elements.Span[0];
var streamInfo = streams[streamVariableId];
// Set this base for OpStore/OpLoad stream R/W analysis
currentBase = streamVariableId;
currentStreamKind = streamKind;
}
// Any read or write through an access chain will be treated as doing it on the main variable.
// i.e., streams.A.B will share same streamInfo as streams.AView on GitHub (pinned to 96fad776d2)