stride3d/stride · error · InvalidOperationException

During mix phase, shaders generics are expected to be fully…

Error message

During mix phase, shaders generics are expected to be fully resolved

What it means

ValidateGenericParameters enforces that by the Mix resolve step every generic parameter is marked Resolved. If any genericParameters entry still has Resolved == false during mixing, the library throws InvalidOperationException — mixing cannot proceed with unresolved generics because names and constants would be ambiguous.

Solutions

  1. Ensure the instantiation supplies concrete constant values for all generics before the mix phase.
  2. Check that every shader referenced in generic expressions is imported so Substitute/ResolveGenericArg can resolve them.
  3. Run the resolve step (ResolveStep.Compile) before mixing so generic parameters get marked Resolved.

Example fix

// before
BuildInheritanceListIncludingSelf(loader, ctx, source, macros, list, ResolveStep.Mix);
// after (resolve first, then mix)
BuildInheritanceListIncludingSelf(loader, ctx, source, macros, list, ResolveStep.Compile);
BuildInheritanceListIncludingSelf(loader, ctx, source, macros, list, ResolveStep.Mix);
Defensive patterns

Strategy: validation

Validate before calling

if (resolveStep == ResolveStep.Mix && genericParameters.Any(p => !p.Resolved))
    throw new InvalidOperationException($"Unresolved generics before mix: {string.Join(",", genericParameters.Where(p => !p.Resolved).Select(p => p.Name))}");

Type guard

bool AllResolved(IEnumerable<GenericParameter> ps) => ps.All(p => p.Resolved);

Try / catch

try { ValidateGenericParameters(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("fully resolved")) { /* rerun the resolve pass before mixing */ }

Prevention

When it happens

Trigger: Running the mixin/mix phase (ResolveStep.Mix) when a generic argument failed to substitute earlier — e.g. a GenericParamExpr that referenced a parent's generic not present in importArgsByName, or an argument that never got a constant value.

Common situations: Inheriting from a parameterized mixin whose generic arguments themselves reference generics of an unimported shader; an instantiation that skipped the earlier resolve pass; a bug where resolution silently failed and returned the expression unresolved.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Class.cs:372

            var constantBuffer = expr.EmitToBuffer();

            context.RemoveAt(instructionIndex);

            var bound = context.Bound;
            context.InsertWithoutDuplicates(ref instructionIndex, genericParameter.ResultId, constantBuffer);
            context.Bound = bound;

            return true;
        }

        public override void ValidateGenericParameters(string classNameWithGenerics, List<GenericParameter> genericParameters)
        {
            // Fully resolved?
            if (resolveStep == ResolveStep.Mix)
            {
                if (!genericParameters.All(x => x.Resolved))
                {
                    throw new InvalidOperationException("During mix phase, shaders generics are expected to be fully resolved");
                }
            }
        }

        public override void PostProcess(string classNameWithGenerics)
        {
            if (resolveStep == ResolveStep.Mix)
            {
                classSource.ClassName = classNameWithGenerics;
                classSource.GenericArguments = [];
            }
        }
    }

    private static void InstantiateGenericShader(ref ShaderBuffers shaderBuffers, string classNameWithGenerics, GenericResolver genericResolver, IExternalShaderLoader shaderLoader, ReadOnlySpan<ShaderMacro> macros)
    {
        var resolvedLinks = new Dictionary<int, string>();
        var semantics = new Dictionary<string, string>();

View on GitHub (pinned to 96fad776d2)