stride3d/stride · error · InvalidOperationException

Method was found but a base call can't be performed on a…

Error message

Method {methodGroupEntry.Name} was found but a base call can't be performed on a stage method from a non-stage method

What it means

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.

Solutions

  1. Remove the base call and call the stage method directly, or restructure so both caller and target are stage methods.
  2. Move the calling code into a stage method if base-call semantics are required.
  3. Provide an override of the method in the mixin hierarchy and base-call that instead.
  4. Use composition (calling the method on a composed shader instance) rather than inheritance-style base calls across the stage boundary.

Example fix

// before (base call to a stage method from a non-stage method)
void MyHelper() { base.ComputeShading(); }
// after
void MyHelper() { ComputeShading(); } // direct call, or make MyHelper a stage method
Defensive patterns

Strategy: validation

Validate before calling

// Only emit base calls for methods resolved within the same mixin, not stage methods
bool baseCallAllowed = !foundInStage; // stage-resolved methods cannot be base-called from non-stage methods
if (isBase && !baseCallAllowed)
    throw new InvalidOperationException("base.Call() on stage methods is not allowed from non-stage methods; call the method directly");

Try / catch

try { var mixed = mixer.Process(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("base call can't be performed on a stage method"))
{
    log.Error(ex, "Replace base.StageMethod() with a direct call, or move the caller into a stage method");
    throw;
}

Prevention

When it happens

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

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

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

                    bool foundInStage = false;
                    if (!instanceMixinGroup.MethodGroups.TryGetValue(functionId, out var methodGroupEntry))
                    {
                        // Try again as a stage method (only if not a base call)
                        if (instanceMixinGroup.Stage == null || !instanceMixinGroup.Stage.MethodGroups.TryGetValue(functionId, out methodGroupEntry))
                            throw new InvalidOperationException($"Can't find method group info for {context.Names[functionId]}");
                        foundInStage = true;
                    }

                    // Default: most derived implementation
                    var selectedMethod = methodGroupEntry.Methods[^1];

                    // Process base call
                    if (isBase)
                    {
                        // We currently do not allow calling base stage method from a non-stage method
                        // (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)
                        if (foundInStage)
                            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");

                        // 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}");
                    }

View on GitHub (pinned to 96fad776d2)