stride3d/stride · error · InvalidOperationException

No composition was supplied for

Error message

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.

What it means

When merging a mixin node, every composition-type variable (pointer to ShaderSymbol or array thereof) declared by the shader must have a supplied composition. If mixinSource.Compositions lacks the key, the mixer throws a descriptive InvalidOperationException instead of a bare dictionary KeyNotFoundException, hinting that a `stage compose` promotion left the value at a nested path.

Solutions

  1. Supply the missing composition in the mixin tree, e.g. mixinTree["Key"] = otherShaderSource
  2. Remove the `stage compose`/promotion so the declaration matches where values are provided
  3. Fix key spelling so it matches the composed variable name
  4. Check the error's list of available keys to see what the node actually has

Example fix

// before
var shader = new ShaderMixinSource { Mixins = { baseShader } }; // missing composition for 'stream'
// after
var shader = new ShaderMixinSource { Mixins = { baseShader } };
shader.Compositions.Add("stream", childShaderSource); // matches declared compose variable
Defensive patterns

Strategy: try-catch

Validate before calling

foreach (var kv in declaredComposeVariables)
    if (!mixinSource.Compositions.ContainsKey(kv.Key))
        throw new InvalidOperationException($"Missing composition for '{kv.Key}'");

Try / catch

try { result = mixer.MergeSDSL(tree); }
catch (InvalidOperationException ex) when (ex.Message.Contains("No composition was supplied for")) {
    fixCompositionKey(ex, mixinTree); // message lists available keys
}

Prevention

When it happens

Trigger: MergeSDSL/MergeMixinNode encounters a shader declaring `compose X` (or stage-composed) variable while the current mixin source provides no entry for that key; the declaring shader was promoted to this node via `stage compose` but its value was only supplied at a nested composition path; a composition key typo in the mixin tree.

Common situations: Forget ting to set a required compose slot on a ShaderSource/MixinNode before mixing; renaming a composition channel in the shader but not in the hosting code; using `stage compose` inheritance where the parent expects the child's value hoisted to the root path.

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/4803cc3419230a3b. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:337

        var mixinNode = new MixinNode(stage, currentCompositionPath);
        var contextStart = context.Count;

        // Merge all classes from mixinSource.Mixins in main buffer
        ProcessMixinClasses(globalContext, context, buffer, mixinSource, mixinNode);

        BuildTypesAndMethodGroups(globalContext, context, buffer, mixinNode);

        // Compositions (recursive)
        foreach (var shader in mixinNode.Shaders)
        {
            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

View on GitHub (pinned to 96fad776d2)