stride3d/stride · error · InvalidOperationException
Composition variable
Error message
Composition variable {variable.Key} is not an array but had {compositionMixins.Length} entries What it means
A composition variable not declared as an array (pointer base type is a plain ShaderSymbol, not ArrayType of ShaderSymbol) must receive exactly one mixin. If the supplied composition has more than one entry, MergeMixinNode throws InvalidOperationException because multiple shaders cannot fill a non-array composition slot.
Solutions
- Declare the variable as an array composition (`compose MyShader[]`) if multiple entries are intended
- Supply exactly one mixin for the non-array composition key
- Deduplicate or pick one source when building the composition list
Example fix
// before shaderClass: `compose ShadingModel Shader;` // with 2 entries supplied // after shaderClass: `compose ShadingModel[] Shader;` // or supply a single entry
Defensive patterns
Strategy: validation
Validate before calling
if (!isDeclaredAsArray && compositionEntries.Count != 1)
throw new InvalidOperationException("Non-array composition needs exactly one entry"); Type guard
bool IsArrayComposition(PointerType p) => p.BaseType is ArrayType { BaseType: ShaderSymbol }; Try / catch
try { result = mixer.MergeSDSL(tree); }
catch (InvalidOperationException ex) when (ex.Message.Contains("is not an array but had")) {
reduceToOneCompositionEntry(key);
} Prevention
- Match composition cardinality to the declaration (`compose X` vs `compose X[]`)
- Deduplicate mixin lists before assigning to compose slots
- Review programmatic composition building code
When it happens
Trigger: Assigning multiple shader sources to a composition key whose declaration is `compose ShaderClass` (not `compose ShaderClass[]`); pushing several mixins into a non-array compose channel during tree building.
Common situations: Programmatically appending multiple effects to a single compose slot; mis-declaring `compose` without `[]` while feeding a list; copy-pasted array composition code applied to a scalar composition.
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
- No composition was supplied for
- Could not find cbuffer member link info for
- [Color] attribute can only be applied on float3/float4…
- Unsupported float vector size
- Unsupported int vector size
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/bddb3e68346fde77.
Report an issue: GitHub.
Appendix: source
Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:347
{
foreach (var variable in shader.Variables)
{
if (variable.Value.Type is PointerType pointer && pointer.BaseType is ShaderSymbol or ArrayType { BaseType: ShaderSymbol })
{
// Every piece of context needed to act on this is in scope, and the dictionary
// indexer would throw a bare "The given key was not present" instead.
if (!mixinSource.Compositions.TryGetValue(variable.Key, out var compositionMixins))
throw new InvalidOperationException(
$"No composition was supplied for '{variable.Key}', declared as '{variable.Value.Type}' by shader '{shader.ShaderName}', "
+ $"while merging the mixin node '{currentCompositionPath ?? "<root>"}' (root: {mixinNode.IsRoot}). "
+ $"That node only has [{string.Join(", ", mixinSource.Compositions.Keys)}]. "
+ $"A `stage compose` is the usual cause: the shader declaring it was promoted to this node, "
+ $"but its value was supplied at a nested composition path and nothing carried it up.");
var isCompositionArray = pointer.BaseType is ArrayType { BaseType: ShaderSymbol };
if (!isCompositionArray && compositionMixins.Length != 1)
throw new InvalidOperationException($"Composition variable {variable.Key} is not an array but had {compositionMixins.Length} entries");
var compositionResults = new MixinNode[compositionMixins.Length];
for (int i = 0; i < compositionMixins.Length; ++i)
{
var localKey = variable.Key;
if (isCompositionArray)
localKey += $"[{i}]";
// TODO: Review: it seems like Stride compose variable the opposite way that we expect
// Let's change it so that it becomes {currentCompositionPath}.{localKey}!
var compositionPath = currentCompositionPath != null ? $"{localKey}.{currentCompositionPath}" : localKey;
compositionResults[i] = MergeMixinNode(globalContext, context, buffer, compositionMixins[i], mixinNode.IsRoot ? mixinNode : mixinNode.Stage, compositionPath);
}
if (isCompositionArray)
mixinNode.CompositionArrays.Add(variable.Value.Id, compositionResults);
else
mixinNode.Compositions.Add(variable.Value.Id, compositionResults[0]);
}View on GitHub (pinned to 96fad776d2)