{"record":{"id":"62bfbe8fac1ca133","repo":"stride3d/stride","slug":"importing-stage-only-methods-variables-is-only-possible-at","errorCode":null,"errorMessage":"importing stage-only methods/variables is only possible at the root mixin","messagePattern":"importing stage-only methods/variables is only possible at the root mixin","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":421,"sourceCode":"    }\n\n    private static string ComposeLinkName(string linkName, string? compositionPath = null)\n    {\n        if (compositionPath != null)\n            linkName += $\".{compositionPath}\";\n        return linkName;\n    }\n\n    // Append CompositionPath to \"Link\" for any non-stage variable\n    // Also force-emit the missing \"Link\" decorations\n\n    private ShaderInfo MergeClassInBuffers(MixinGlobalContext globalContext, SpirvContext context, SpirvBuffer buffer, MixinNode mixinNode, ShaderClassInstantiation shaderClass, TypeDuplicateHelper typeDuplicateInserter)\n    {\n        var isRootMixin = mixinNode.Stage == null;\n        if (shaderClass.ImportStageOnly)\n        {\n            if (!isRootMixin)\n                throw new InvalidOperationException(\"importing stage-only methods/variables is only possible at the root mixin\");\n        }\n\n        var shaderBuffers = shaderClass.Buffer ?? throw new InvalidOperationException($\"Shader buffers not loaded for {shaderClass.ClassName}\");\n        var offset = context.Bound;\n        var resourceGroupOffset = context.ResourceGroupBound;\n\n        // Remember when we started to add instructions in both context and main buffer\n        var shaderStart = buffer.Count;\n        var contextStart = context.Count;\n        var names = new Dictionary<int, string>();\n\n        var forbiddenIds = new HashSet<int>();\n        var remapIds = new Dictionary<int, int>();\n        var removedIds = new HashSet<int>();\n\n        bool isContext = true;\n\n        // Note: FunctionType is only required when looking for stage function","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L403-L439","documentation":"Importing stage-only methods/variables (shaderClass.ImportStageOnly, SDSL `import stage`) is only legal at the root mixin — the node with no Stage. MergeClassInBuffers enforces this and throws InvalidOperationException when such an import appears in a nested/staged mixin, because stage-only symbols cannot be replicated into a non-root stage context.","triggerScenarios":"A shader using `import stage` (or ImportStageOnly=true) is mixed at a non-root node (mixinNode.Stage != null) during MergeClassInBuffers via shaderInfo; composing an `import stage` shader into a nested composition path.","commonSituations":"Applying an `import stage` utility shader as a nested composition instead of the root; inheritance chains where a mid-level shader imports stage-only symbols; refactor moving an `import stage` shader deeper into the tree.","solutions":["Move the `import stage` shader to the root of the mixin tree","Remove `import stage` (use regular import) if stage-only symbols aren't required","Restructure composition so stage-only symbols are only referenced from the root mixin"],"exampleFix":"// before\nvar nested = new ShaderMixinSource { Mixins = { importStageShader } }; // used as composition of root\n// after\nvar root = new ShaderMixinSource { Mixins = { importStageShader, otherMixin } }; // import stage at root","handlingStrategy":"try-catch","validationCode":"if (shaderClass.ImportStageOnly && mixinNode.Stage != null)\n    throw new InvalidOperationException(\"import stage shader must be at root mixin\");","typeGuard":null,"tryCatchPattern":"try { result = mixer.MergeSDSL(tree); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"importing stage-only\")) {\n    moveShaderToRootMixin();\n}","preventionTips":["Place `import stage` shaders only at the tree root","Audit inheritance chains for mid-level stage imports","Prefer plain `import` unless stage-only symbols are truly needed"],"tags":["shaders","sdsl","stage","mixin"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}