{"record":{"id":"8d89fd99b7bbf657","repo":"stride3d/stride","slug":"trying-to-call-an-abstract-method-selectedmethod-shader","errorCode":null,"errorMessage":"Trying to call an abstract method {selectedMethod.Shader.ShaderName}.{methodGroupEntry.Name}","messagePattern":"Trying to call an abstract method (.+?)\\.(.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs","lineNumber":1066,"sourceCode":"                        // 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))\n                    throw new InvalidOperationException($\"Can't find method group info for {context.Names[function.ResultId]}\");\n            }\n            else if (i.Data.Op == Op.OpFunctionEnd)\n            {","sourceCodeStart":1048,"sourceCodeEnd":1084,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs#L1048-L1084","documentation":"After selecting the most-derived (or base) implementation for a call, the mixer checks the selected method's FunctionFlagsMask.Abstract flag. Abstract methods have no body in SDSL; calling one would produce invalid generated code, so the mixer rejects it and names the declaring shader and method.","triggerScenarios":"ShaderMixer constructor: selectedMethod (from methodGroupEntry.Methods, default last, or the base-call result) has the Abstract flag set and is targeted by a member-access call.","commonSituations":"Invoking a method that is only declared abstract in a base shader and never given a concrete override anywhere in the composed hierarchy; accidentally selecting the abstract root because no override was composed; typos in override signatures so the override didn't join the method group.","solutions":["Provide a concrete implementation of the method in a shader that is composed into the hierarchy.","Fix the override's signature so it joins the same method group as the abstract declaration.","Guard the call site so the abstract method is not invoked when unimplemented.","Remove the abstract declaration if a default implementation is acceptable."],"exampleFix":"// before: abstract declaration only\nabstract void ComputeColor();\n// after: concrete override in derived shader\noverride void ComputeColor() { /* implementation */ }","handlingStrategy":"validation","validationCode":"// Before calling, ensure the selected implementation is concrete\nif ((selectedMethod.Flags & FunctionFlagsMask.Abstract) != 0)\n    throw new InvalidOperationException($\"'{selectedMethod.Shader.ShaderName}.{methodGroup.Name}' is abstract; provide a concrete override before calling\");","typeGuard":null,"tryCatchPattern":"try { var mixed = mixer.Process(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Trying to call an abstract method\"))\n{\n    log.Error(ex, \"Abstract SDSL method invoked; add an override in a composed shader or guard the call site\");\n    throw;\n}","preventionTips":["Give every abstract SDSL method at least one concrete override in the composed hierarchy.","Match override signatures exactly so they join the same method group as the abstract declaration.","Treat abstract SDSL methods like interface members: verify implementations exist per composition.","Keep a shader-composition smoke test in CI."],"tags":["shader","sdsl","abstract-method","method-resolution"],"backgroundTag":"abstract-method-not-implemented","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"}