stride3d/stride · error · InvalidOperationException
Exception of type 'System.InvalidOperationException' was…
Error message
Exception of type 'System.InvalidOperationException' was thrown.
What it means
During InstantiateGenericShader, when an OpTypeArray is found the builder looks up its Length id in the context buffer and expects an instruction to exist. If TryGetInstructionById fails, the invariant that array-length constants are present in the buffer is broken and a bare InvalidOperationException is thrown.
Solutions
- Ensure the array length constant (OpConstant) is emitted into the context buffer, not the main buffer, before instantiation.
- Regenerate the shader buffers from source if they come from a stale cache.
- If manipulating instructions manually, never remove the instruction whose result-id an OpTypeArray.Length references.
Example fix
// before context.RemoveAt(instructionIndex); // removes constant later referenced by OpTypeArray.Length // after (keep or replace preserving result id) context.Replace(instructionIndex, new OpConstantInt(resultId, type, newValue));
Defensive patterns
Strategy: try-catch
Validate before calling
if (!shaderBuffers.Context.GetBuffer().TryGetInstructionById(typeArrayLengthId, out var len) || len.Op != Op.OpConstant)
throw new InvalidOperationException($"Array length id {typeArrayLengthId} is not a constant in the context buffer"); Type guard
bool HasConstantLength(ShaderBuffers b, int lengthId) => b.Context.GetBuffer().TryGetInstructionById(lengthId, out var i) && i.Op == Op.OpConstant;
Try / catch
try { result = builder.InstantiateGenericShader(...); }
catch (InvalidOperationException ex) when (ex.StackTrace.Contains("InstantiateGenericShader")) { /* rebuild buffers from source and retry once */ } Prevention
- Never remove instructions whose result-ids are referenced by OpTypeArray.Length
- Keep array-length constants in the context buffer, not the main buffer
- Invalidate cached buffers whenever the compiler version changes
When it happens
Trigger: Instantiating a generic shader whose buffer contains an OpTypeArray whose Length result-id is not present in shaderBuffers.Context.GetBuffer() — the defining constant was dropped, lives in another buffer, or the id is stale.
Common situations: Arrays sized by a generic constant where the constant was replaced/removed during generic substitution; using a buffer pair (Context/Buffer) that got split incorrectly; cached shader buffers missing context instructions.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Cannot find type instruction for id
- Use LiteralArray .From instead
- The path [ ] contains non-integer index on an array.
- The path [ ] contains a non-valid item id on an array.
- The destination array must be of same length or larger…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/30965ccee9a474f7.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Class.cs:482
resolvedArgId = innerArgs[innerRef.Index];
else
break; // Can't resolve further
}
// Extract the resolved constant and its dependencies from the context buffer
var constantBuffer = SpirvContext.ExtractConstantFromBuffer(resolvedArgId, shaderBuffers.Context.GetBuffer());
// Remove the GenericReference and insert the resolved constant with the same ResultId
shaderBuffers.Context.RemoveAt(index);
shaderBuffers.Context.InsertWithoutDuplicates(ref index, genRef.ResultId, constantBuffer);
index--; // adjust for loop increment
}
}
if (i.Op == Op.OpTypeArray && (OpTypeArray)i is { } typeArray)
{
// Make sure constant is a proper OpConstant (i.e. not an OpSpecConstant/OpSpecConstantOp)
if (!shaderBuffers.Context.GetBuffer().TryGetInstructionById(typeArray.Length, out var lengthInstruction))
throw new InvalidOperationException();
if (lengthInstruction.Op != Op.OpConstant)
{
var expr = ConstantExpression.ParseFromBuffer(typeArray.Length, shaderBuffers.Context.GetBuffer(), shaderBuffers.Context);
if (expr.TryEvaluate(out var value) && value != null)
{
var resultType = lengthInstruction.Data.IdResultType!.Value;
var resultId = lengthInstruction.Data.IdResult!.Value;
if (value is int or long)
shaderBuffers.Context.Replace(lengthInstruction.Index, new OpConstant<int>(resultType, resultId, System.Convert.ToInt32(value)));
else if (value is float or double)
shaderBuffers.Context.Replace(lengthInstruction.Index, new OpConstant<float>(resultType, resultId, System.Convert.ToSingle(value)));
}
}
}
}
//Console.WriteLine($"[Shader] Instantiating {classNameWithGenerics}");
View on GitHub (pinned to 96fad776d2)