{"record":{"id":"4803cc3419230a3b","repo":"stride3d/stride","slug":"no-composition-was-supplied-for-variable-key-declared-as","errorCode":null,"errorMessage":"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.","messagePattern":"No composition was supplied for '(.+?)', declared as '(.+?)' by shader '(.+?)', while merging the mixin node '(.+?)' \\(root: (.+?)\\)\\. That node only has \\[(.+?)\\]\\. 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\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":337,"sourceCode":"        var mixinNode = new MixinNode(stage, currentCompositionPath);\n        var contextStart = context.Count;\n\n        // Merge all classes from mixinSource.Mixins in main buffer\n        ProcessMixinClasses(globalContext, context, buffer, mixinSource, mixinNode);\n\n        BuildTypesAndMethodGroups(globalContext, context, buffer, mixinNode);\n\n        // Compositions (recursive)\n        foreach (var shader in mixinNode.Shaders)\n        {\n            foreach (var variable in shader.Variables)\n            {\n                if (variable.Value.Type is PointerType pointer && pointer.BaseType is ShaderSymbol or ArrayType { BaseType: ShaderSymbol })\n                {\n                    // Every piece of context needed to act on this is in scope, and the dictionary\n                    // indexer would throw a bare \"The given key was not present\" instead.\n                    if (!mixinSource.Compositions.TryGetValue(variable.Key, out var compositionMixins))\n                        throw new InvalidOperationException(\n                            $\"No composition was supplied for '{variable.Key}', declared as '{variable.Value.Type}' by shader '{shader.ShaderName}', \"\n                            + $\"while merging the mixin node '{currentCompositionPath ?? \"<root>\"}' (root: {mixinNode.IsRoot}). \"\n                            + $\"That node only has [{string.Join(\", \", mixinSource.Compositions.Keys)}]. \"\n                            + $\"A `stage compose` is the usual cause: the shader declaring it was promoted to this node, \"\n                            + $\"but its value was supplied at a nested composition path and nothing carried it up.\");\n\n                    var isCompositionArray = pointer.BaseType is ArrayType { BaseType: ShaderSymbol };\n\n                    if (!isCompositionArray && compositionMixins.Length != 1)\n                        throw new InvalidOperationException($\"Composition variable {variable.Key} is not an array but had {compositionMixins.Length} entries\");\n\n                    var compositionResults = new MixinNode[compositionMixins.Length];\n                    for (int i = 0; i < compositionMixins.Length; ++i)\n                    {\n                        var localKey = variable.Key;\n                        if (isCompositionArray)\n                            localKey += $\"[{i}]\";\n                        // TODO: Review: it seems like Stride compose variable the opposite way that we expect","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L319-L355","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Supply the missing composition in the mixin tree, e.g. mixinTree[\"Key\"] = otherShaderSource","Remove the `stage compose`/promotion so the declaration matches where values are provided","Fix key spelling so it matches the composed variable name","Check the error's list of available keys to see what the node actually has"],"exampleFix":"// before\nvar shader = new ShaderMixinSource { Mixins = { baseShader } }; // missing composition for 'stream'\n// after\nvar shader = new ShaderMixinSource { Mixins = { baseShader } };\nshader.Compositions.Add(\"stream\", childShaderSource); // matches declared compose variable","handlingStrategy":"try-catch","validationCode":"foreach (var kv in declaredComposeVariables)\n    if (!mixinSource.Compositions.ContainsKey(kv.Key))\n        throw new InvalidOperationException($\"Missing composition for '{kv.Key}'\");","typeGuard":null,"tryCatchPattern":"try { result = mixer.MergeSDSL(tree); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"No composition was supplied for\")) {\n    fixCompositionKey(ex, mixinTree); // message lists available keys\n}","preventionTips":["Populate every compose slot declared by mixed shaders","Keep composition keys in sync when renaming shader channels","Avoid `stage compose` unless values are hoisted to the promoted node's path"],"tags":["shaders","sdsl","composition","mixin"],"backgroundTag":"missing-required-argument","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}