stride3d/stride · error · InvalidOperationException

Trying to call an abstract method

Error message

Trying to call an abstract method {selectedMethod.Shader.ShaderName}.{methodGroupEntry.Name}

What it means

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.

Solutions

  1. Provide a concrete implementation of the method in a shader that is composed into the hierarchy.
  2. Fix the override's signature so it joins the same method group as the abstract declaration.
  3. Guard the call site so the abstract method is not invoked when unimplemented.
  4. Remove the abstract declaration if a default implementation is acceptable.

Example fix

// before: abstract declaration only
abstract void ComputeColor();
// after: concrete override in derived shader
override void ComputeColor() { /* implementation */ }
Defensive patterns

Strategy: validation

Validate before calling

// Before calling, ensure the selected implementation is concrete
if ((selectedMethod.Flags & FunctionFlagsMask.Abstract) != 0)
    throw new InvalidOperationException($"'{selectedMethod.Shader.ShaderName}.{methodGroup.Name}' is abstract; provide a concrete override before calling");

Try / catch

try { var mixed = mixer.Process(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Trying to call an abstract method"))
{
    log.Error(ex, "Abstract SDSL method invoked; add an override in a composed shader or guard the call site");
    throw;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/8d89fd99b7bbf657. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Compilers/SDSL/ShaderMixer.cs:1066

                        // Is it a base call? if yes, find the direct parent
                        // Let's find the method in same group just before ours
                        bool baseMethodFound = false;
                        for (int j = methodGroupEntry.Methods.Count - 1; j >= 0; --j)
                        {
                            if (methodGroupEntry.Methods[j].Shader.ShaderIndex < currentShader.ShaderIndex)
                            {
                                selectedMethod = methodGroupEntry.Methods[j];
                                baseMethodFound = true;
                                break;
                            }
                        }

                        if (!baseMethodFound)
                            throw new InvalidOperationException($"Can't find a base method for {methodGroupEntry.Name}");
                    }

                    if ((selectedMethod.Flags & FunctionFlagsMask.Abstract) != 0)
                        throw new InvalidOperationException($"Trying to call an abstract method {selectedMethod.Shader.ShaderName}.{methodGroupEntry.Name}");
                    functionId = selectedMethod.MethodId;

                    memberAccesses.Add(memberAccess.ResultId, functionId);
                }
                else
                {
                    throw new InvalidOperationException($"Member {memberAccess.Member} not found");
                }

                SetOpNop(i.Data.Memory.Span);
            }
            else if (i.Data.Op == Op.OpFunction && (OpFunction)i is { } function && temp[index + 1].Op == Op.OpFunctionMetadataSDSL && (OpFunctionMetadataSDSL)temp[index + 1] is { } functionInfo)
            {
                if (!mixinNode.MethodGroups.TryGetValue(function.ResultId, out var methodGroupEntry))
                    throw new InvalidOperationException($"Can't find method group info for {context.Names[function.ResultId]}");
            }
            else if (i.Data.Op == Op.OpFunctionEnd)
            {

View on GitHub (pinned to 96fad776d2)