{"record":{"id":"2d47265fad06750b","repo":"stride3d/stride","slug":"can-t-find-a-base-method-for-methodgroupentry-name","errorCode":null,"errorMessage":"Can't find a base method for {methodGroupEntry.Name}","messagePattern":"Can't find a base method for (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":1062,"sourceCode":"                        // (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\n                    if ((selectedMethod.Flags & FunctionFlagsMask.Abstract) != 0)\n                        throw new InvalidOperationException($\"Trying to call an abstract method {selectedMethod.Shader.ShaderName}.{methodGroupEntry.Name}\");\n                    functionId = selectedMethod.MethodId;\n\n                    memberAccesses.Add(memberAccess.ResultId, functionId);\n                }\n                else\n                {\n                    throw new InvalidOperationException($\"Member {memberAccess.Member} not found\");\n                }\n\n                SetOpNop(i.Data.Memory.Span);\n            }\n            else if (i.Data.Op == Op.OpFunction && (OpFunction)i is { } function && temp[index + 1].Op == Op.OpFunctionMetadataSDSL && (OpFunctionMetadataSDSL)temp[index + 1] is { } functionInfo)\n            {\n                if (!mixinNode.MethodGroups.TryGetValue(function.ResultId, out var methodGroupEntry))","sourceCodeStart":1044,"sourceCodeEnd":1080,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L1044-L1080","documentation":"For a base call within the same mixin, the mixer walks the method group's Methods list backwards to find the implementation registered just before the current shader's (the direct parent). If no earlier implementation exists, there is no base method to call — the current shader provides the base-most implementation of that method group.","triggerScenarios":"ShaderMixer constructor handles a base call (isBase == true) on a non-stage method group; the backward scan over methodGroupEntry.Methods finds no method with a ShaderIndex before the caller's, leaving baseMethodFound == false.","commonSituations":"Calling base.Method() in the first (root) shader that declares the method; the parent shader no longer overrides the method after a refactor; method declared abstract in all ancestors so no concrete base exists.","solutions":["Remove the base call — the current shader is the base-most implementation.","Add a concrete implementation of the method in a parent shader in the inheritance chain.","Ensure the parent shader is actually composed (ShaderIndex ordering) before this shader.","Give the method a default body instead of leaving it abstract if a base behavior is expected."],"exampleFix":"// before: base shader declares method, derived calls base.Method()\nvoid Method() { base.Method(); } // no base impl\n// after\nvoid Method() { /* own implementation, no base call */ }","handlingStrategy":"validation","validationCode":"// A base call requires a strictly earlier implementation in the method group\nbool hasBase = methodGroup.Methods.Any(m => m.ShaderIndex < currentShaderIndex);\nif (isBase && !hasBase)\n    throw new InvalidOperationException($\"'{methodGroup.Name}' has no base implementation; remove the base call or add a parent override\");","typeGuard":null,"tryCatchPattern":"try { var mixed = mixer.Process(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Can't find a base method\"))\n{\n    log.Error(ex, \"base.Method() called in the base-most implementation; drop the call or add a concrete parent implementation\");\n    throw;\n}","preventionTips":["Only call base.Method() when a parent shader in the chain provides a concrete body.","After refactoring inheritance chains, re-audit base calls at every level.","Do not call base on methods declared abstract in all ancestors.","Compile shaders in CI to catch these during development."],"tags":["shader","sdsl","base-call","inheritance"],"backgroundTag":"resource-not-found","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"}