stride3d/stride · error · NotSupportedException

Type ' ' is not supported as a SymbolType.

Error message

Type '{typeof(T)}' is not supported as a SymbolType.

What it means

SymbolType.Of<T>() maps a small fixed set of .NET primitive types (scalars, System.Numerics vectors and matrices) to their shader SymbolType equivalents. If T is any other type, the switch's default arm throws NotSupportedException. It is an internal whitelist lookup, not a general converter.

Solutions

  1. Use a supported T: one of void, bool, byte, sbyte, short, ushort, Half, int, uint, float, double, System.Numerics.Vector2/3/4, Matrix3x2, Matrix4x4.
  2. If you need a custom type, construct the SymbolType directly (ScalarType, VectorType.From, MatrixType.From) instead of calling Of<T>.
  3. If the type should legitimately be supported, add a mapping arm to SymbolType.Of<T> in SymbolTypes.cs.
  4. Guard with a whitelist check before calling to fail fast with a clearer message.

Example fix

// before
var t = SymbolType.Of<long>(); // NotSupportedException
// after
var t = ScalarType.Int64; // 'long' maps to Scalar.Int64
Defensive patterns

Strategy: validation

Validate before calling

static readonly HashSet<Type> Supported = new() {
    typeof(void), typeof(bool), typeof(byte), typeof(sbyte),
    typeof(short), typeof(ushort), typeof(Half), typeof(int),
    typeof(uint), typeof(float), typeof(double),
    typeof(System.Numerics.Vector2), typeof(System.Numerics.Vector3),
    typeof(System.Numerics.Vector4), typeof(System.Numerics.Matrix3x2),
    typeof(System.Numerics.Matrix4x4) };

if (!Supported.Contains(typeof(T)))
    throw new ArgumentException($"{typeof(T)} has no SymbolType mapping");
var t = SymbolType.Of<T>();

Type guard

static bool HasSymbolType<T>() =>
    typeof(T) == typeof(void) || typeof(T) == typeof(bool) ||
    typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte) ||
    typeof(T) == typeof(short) || typeof(T) == typeof(ushort) ||
    typeof(T) == typeof(Half) || typeof(T) == typeof(int) ||
    typeof(T) == typeof(uint) || typeof(T) == typeof(float) ||
    typeof(T) == typeof(double) ||
    typeof(System.Numerics.Vector2).IsAssignableFrom(typeof(T)) ||
    typeof(System.Numerics.Vector3).IsAssignableFrom(typeof(T)) ||
    typeof(System.Numerics.Vector4).IsAssignableFrom(typeof(T)) ||
    typeof(System.Numerics.Matrix3x2).IsAssignableFrom(typeof(T)) ||
    typeof(System.Numerics.Matrix4x4).IsAssignableFrom(typeof(T));

Try / catch

try { var t = SymbolType.Of<T>(); }
catch (NotSupportedException ex)
{
    // fall back to manual SymbolType construction or report unsupported T
}

Prevention

When it happens

Trigger: Calling SymbolType.Of<T>() with a generic argument outside the supported set: e.g. Of<long>(), Of<Half> on platforms where it's unmapped, Of<decimal>(), Of<Vector2> from a different namespace, custom structs, or reference types like string.

Common situations: Developers writing generic shader-parameter binding code assume Of<T> works for any numeric type (e.g. long, decimal); refactoring a uniform struct to a type not on the whitelist; using System.Numerics analogues or user-defined vector types that are not the exact typeof(Vector3) etc.

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/4f362c52ee28e0a2. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Core/SymbolTypes.cs:162

            var t when t == typeof(bool) => ScalarType.From("bool"),
            var t when t == typeof(byte) => ScalarType.From("byte"),
            var t when t == typeof(sbyte) => ScalarType.From("sbyte"),
            var t when t == typeof(short) => ScalarType.From("short"),
            var t when t == typeof(ushort) => ScalarType.From("ushort"),
            var t when t == typeof(Half) => ScalarType.From("half"),
            var t when t == typeof(int) => ScalarType.From("int"),
            var t when t == typeof(uint) => ScalarType.From("uint"),
            var t when t == typeof(float) => ScalarType.From("float"),
            var t when t == typeof(double) => ScalarType.From("double"),

            var t when t == typeof(System.Numerics.Vector2) => VectorType.From("float2"),
            var t when t == typeof(System.Numerics.Vector3) => VectorType.From("float3"),
            var t when t == typeof(System.Numerics.Vector4) => VectorType.From("float4"),

            var t when t == typeof(System.Numerics.Matrix3x2) => MatrixType.From("float3x2"),
            var t when t == typeof(System.Numerics.Matrix4x4) => MatrixType.From("float4x4"),

            _ => throw new NotSupportedException($"Type '{typeof(T)}' is not supported as a SymbolType."),
        };
    }
}

public sealed partial record UndefinedType(string TypeName) : SymbolType()
{
    public override string ToString()
    {
        return TypeName;
    }
}

public sealed partial record PointerType(SymbolType BaseType, Specification.StorageClass StorageClass) : SymbolType()
{
    public override string ToId() => $"ptr_{StorageClass}_{BaseType.ToId()}";
    public override string ToString() => $"*{BaseType}";
}

View on GitHub (pinned to 96fad776d2)