stride3d/stride · error · NotSupportedException

Unsupported literal type

Error message

Unsupported literal type: {value.GetType()}

What it means

CreateLiteral converts a boxed .NET object into a strongly-typed Literal for SPIR-V emission. Only bool and the sbyte..double numeric types are mapped; any other runtime type (string, decimal, IntPtr, custom struct, enum, etc.) throws NotSupportedException naming the value's actual type.

Solutions

  1. Convert the value to a supported primitive before calling (e.g. (int)myEnum, Convert.ToDouble(value), (double)(decimal)x)
  2. If the constant comes from deserialization, configure the deserializer to produce int/float/double instead of decimal/string
  3. Extend CreateLiteral's switch to map the needed type (e.g. decimal => new FloatLiteral(new(64,...), (double)i, location))

Example fix

// before
CompileConstant(someDecimalValue); // throws
// after
CompileConstant((double)someDecimalValue);
// or for enums
CompileConstant((int)MyEnum.Value);
Defensive patterns

Strategy: type-guard

Validate before calling

static readonly HashSet<Type> SupportedLiteralTypes = new() {
    typeof(bool), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort),
    typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) };
bool IsSupportedLiteral(object v) => v != null && SupportedLiteralTypes.Contains(v.GetType());

Type guard

static bool IsNumericLiteral(object v) => v is bool or sbyte or byte or short or ushort or int or uint or long or ulong or float or double;

Try / catch

try
{
    var spirvValue = context.CompileConstant(rawValue);
}
catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported literal type"))
{
    // convert to a supported primitive and retry
    var spirvValue = context.CompileConstant(Convert.ToDouble(rawValue));
}

Prevention

When it happens

Trigger: Calling CompileConstant(value) or CreateLiteral(value) with an object whose runtime type is not in {bool, sbyte, byte, short, ushort, int, uint, long, ulong, float, double} — e.g. a decimal, a string, an enum value, or a nullable that boxed as something else.

Common situations: Passing shader constant values loaded from config/JSON where numbers deserialized as decimal or double-string; passing enum constants instead of their underlying integer; using checked arithmetic producing decimal intermediates.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs:286

        return new(Buffer.AddData(new OpConstantComposite(GetOrRegister(type), Bound++, new(values))));
    }

    public Literal CreateLiteral(object value, TextLocation location = default)
    {
        return value switch
        {
            bool i => new BoolLiteral(i, location),
            sbyte i => new IntegerLiteral(new(8, false, true), i, location),
            byte i => new IntegerLiteral(new(8, false, false), i, location),
            short i => new IntegerLiteral(new(16, false, true), i, location),
            ushort i => new IntegerLiteral(new(16, false, false), i, location),
            int i => new IntegerLiteral(new(32, false, true), i, location),
            uint i => new IntegerLiteral(new(32, false, false), i, location),
            long i => new IntegerLiteral(new(64, false, true), i, location),
            ulong i => new IntegerLiteral(new(64, false, false), (long)i, location),
            float i => new FloatLiteral(new(32, true, true), i, location),
            double i => new FloatLiteral(new(64, true, true), i, location),
            _ => throw new NotSupportedException($"Unsupported literal type: {value.GetType()}"),
        };
    }

    public SpirvValue CompileConstant(object value, TextLocation location = default)
    {
        return CompileConstantLiteral(CreateLiteral(value, location));
    }

    public SpirvValue CompileConstantLiteral(Literal literal)
    {
        object literalValue = literal switch
        {
            BoolLiteral lit => lit.Value,
            IntegerLiteral lit => lit.Suffix switch
            {
                { Size: > 32, Signed: false } => lit.ULongValue,
                { Size: > 32, Signed: true } => lit.LongValue,
                { Signed: false } => lit.UIntValue,

View on GitHub (pinned to 96fad776d2)