stride3d/stride · error · InvalidOperationException

Can't parse generic value

Error message

Can't parse generic value

What it means

ResolveGenericValueInBuffer re-parses a generic argument's text value through the SDSL ExpressionParser when the parameter is a ScalarType or VectorType. If ExpressionParser.Expression fails on the text, the library throws InvalidOperationException("Can't parse generic value") because the string is not a valid constant expression.

Solutions

  1. Fix the generic value string so it is a valid SDSL constant expression (e.g. `1.0`, `float2(1.0, 2.0)`).
  2. Ensure numeric values are serialized with InvariantCulture when building the generic argument strings.
  3. Log/inspect the offending textValue and validate it with the Scanner/ExpressionParser before calling the builder.

Example fix

// before
genericValues[i] = value.ToString();
// after
genericValues[i] = Convert.ToString(value, CultureInfo.InvariantCulture);
Defensive patterns

Strategy: validation

Validate before calling

var scanner = new Scanner(textValue);
if (!ExpressionParser.Expression(ref scanner, new ParseResult(), out _))
    throw new ArgumentException($"'{textValue}' is not a valid SDSL constant expression");

Try / catch

try { builder.ResolveGenericValueInBuffer(type, name, index, context, ref idx, value); }
catch (InvalidOperationException ex) when (ex.Message == "Can't parse generic value") { throw new FormatException($"Invalid generic value '{value}' for '{name}'", ex); }

Prevention

When it happens

Trigger: Passing a generic argument string (e.g. from GetOrLoadShader genericValues) that the SDSL ExpressionParser cannot parse as a constant expression — malformed syntax, unsupported tokens, empty text.

Common situations: Loading a cached shader with generic values like `float2(1,2` (unbalanced), a named identifier instead of a literal, or locale-formatted numbers ('1,5' or '1.5f.3'); macros expanding into invalid expressions.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

                    value = genericValue;
                    return true;
                default:
                    throw new NotImplementedException();
            }
        }

        public override bool ResolveGenericValueInBuffer(SymbolType genericParameterType, string genericParameterName, int genericIndex, SpirvContext context, ref int instructionIndex, out string textValue)
        {
            var genericParameter = (OpGenericParameterSDSL)context[instructionIndex];
            var genericValue = genericValues![genericIndex];
            textValue = genericValue;
            switch (genericParameterType)
            {
                case ScalarType or VectorType:
                    var scanner = new Scanner(textValue);
                    ParseResult pr = new ParseResult();
                    if (!ExpressionParser.Expression(ref scanner, pr, out var expression))
                        throw new InvalidOperationException("Can't parse generic value");
                    var localContext = new SpirvContext();
                    var result = expression.CompileConstantValue(new SymbolTable(localContext, null!), localContext, genericParameterType);
                    context.RemoveAt(instructionIndex);
                    context.InsertWithoutDuplicates(ref instructionIndex, genericParameter.ResultId, localContext.GetBuffer());
                    return true;
                case GenericParameterType g:
                    context.Replace(instructionIndex++, new OpConstantStringSDSL(genericParameter.ResultId, genericValue));
                    return true;
                default:
                    throw new NotImplementedException();
            }
        }
    }

    /// <summary>
    /// Instantiate generics using another buffer for the shader constants. If a context is specified, constants will be imported there, otherwise inside the generic shader being instantiated.
    /// </summary>
    class GenericResolverFromInstantiatingBuffer(ShaderClassInstantiation classSource, ResolveStep resolveStep, SpirvContext declaringContext) : GenericResolver

View on GitHub (pinned to 96fad776d2)