{"record":{"id":"25055a6c1e2ff14c","repo":"stride3d/stride","slug":"method-methodgroupentry-name-was-found-but-a-base-call-can-t","errorCode":null,"errorMessage":"Method {methodGroupEntry.Name} was found but a base call can't be performed on a stage method from a non-stage method","messagePattern":"Method (.+?) was found but a base call can't be performed on a stage method from a non-stage method","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":1046,"sourceCode":"                    bool foundInStage = false;\n                    if (!instanceMixinGroup.MethodGroups.TryGetValue(functionId, out var methodGroupEntry))\n                    {\n                        // Try again as a stage method (only if not a base call)\n                        if (instanceMixinGroup.Stage == null || !instanceMixinGroup.Stage.MethodGroups.TryGetValue(functionId, out methodGroupEntry))\n                            throw new InvalidOperationException($\"Can't find method group info for {context.Names[functionId]}\");\n                        foundInStage = true;\n                    }\n\n                    // Default: most derived implementation\n                    var selectedMethod = methodGroupEntry.Methods[^1];\n\n                    // Process base call\n                    if (isBase)\n                    {\n                        // We currently do not allow calling base stage method from a non-stage method\n                        // (if we were to allow them later, we would need to tweak following detection code as ShaderIndex comparison is only valid for items within the same MixinNode)\n                        if (foundInStage)\n                            throw new InvalidOperationException($\"Method {methodGroupEntry.Name} was found but a base call can't be performed on a stage method from a non-stage method\");\n\n                        // Is it a base call? if yes, find the direct parent\n                        // Let's find the method in same group just before ours\n                        bool baseMethodFound = false;\n                        for (int j = methodGroupEntry.Methods.Count - 1; j >= 0; --j)\n                        {\n                            if (methodGroupEntry.Methods[j].Shader.ShaderIndex < currentShader.ShaderIndex)\n                            {\n                                selectedMethod = methodGroupEntry.Methods[j];\n                                baseMethodFound = true;\n                                break;\n                            }\n                        }\n\n                        if (!baseMethodFound)\n                            throw new InvalidOperationException($\"Can't find a base method for {methodGroupEntry.Name}\");\n                    }\n","sourceCodeStart":1028,"sourceCodeEnd":1064,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L1028-L1064","documentation":"A base call (base.MethodName()) resolves the method group, but the selected implementation lives in the Stage rather than the current mixin. The mixer explicitly forbids performing a base call on a stage method from a non-stage method, because ShaderIndex-based parent detection is only valid within the same MixinNode.","triggerScenarios":"ShaderMixer constructor processes a base call (isBase == true); methodGroupEntry was resolved from instanceMixinGroup.Stage.MethodGroups (foundInStage == true) while the calling method is not a stage method.","commonSituations":"Writing base.SomeStageMethod() inside a regular (non-stage) shader method; moving code that used to be a stage method into a plain method while keeping the base call; misunderstanding Stride's stage vs mixin method scoping.","solutions":["Remove the base call and call the stage method directly, or restructure so both caller and target are stage methods.","Move the calling code into a stage method if base-call semantics are required.","Provide an override of the method in the mixin hierarchy and base-call that instead.","Use composition (calling the method on a composed shader instance) rather than inheritance-style base calls across the stage boundary."],"exampleFix":"// before (base call to a stage method from a non-stage method)\nvoid MyHelper() { base.ComputeShading(); }\n// after\nvoid MyHelper() { ComputeShading(); } // direct call, or make MyHelper a stage method","handlingStrategy":"validation","validationCode":"// Only emit base calls for methods resolved within the same mixin, not stage methods\nbool baseCallAllowed = !foundInStage; // stage-resolved methods cannot be base-called from non-stage methods\nif (isBase && !baseCallAllowed)\n    throw new InvalidOperationException(\"base.Call() on stage methods is not allowed from non-stage methods; call the method directly\");","typeGuard":null,"tryCatchPattern":"try { var mixed = mixer.Process(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"base call can't be performed on a stage method\"))\n{\n    log.Error(ex, \"Replace base.StageMethod() with a direct call, or move the caller into a stage method\");\n    throw;\n}","preventionTips":["Never write base.X() for methods defined at stage level from ordinary methods.","Understand Stride's stage vs mixin method scoping before using inheritance-style base calls.","If base-call semantics are needed across the stage boundary, restructure with composition instead.","Keep the calling method and its base target in the same mixin layer."],"tags":["shader","sdsl","base-call","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}