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
- 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.
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
- 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.
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
- Can't find function in current mixin
- Struct not found in shader
- Could not find compositions for expression
- External variable not found
- Can't find method group info for
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)