stride3d/stride · error · NotSupportedException

Unsupported template type

Error message

Unsupported template type {templateType} for Buffer

What it means

SymbolTypes.TryGetBufferType resolves HLSL buffer declarations (Buffer<T>, RWBuffer<T>) to SymbolTypes. Typed buffers may only be templated on a scalar or vector element type; after widening half→float (per VUID-StandaloneSpirv-OpTypeImage-04656), any other template type throws NotSupportedException('Unsupported template type ... for Buffer').

Solutions

  1. Use StructuredBuffer<T> / RWStructuredBuffer<T> instead of Buffer<T> for struct, matrix, or other composite element types.
  2. Keep the typed buffer's template restricted to scalar (float, int, uint) or vector (float2/3/4, int4, ...) types.
  3. If half-based elements are intended, note they are widened to float; use StructuredBuffer<min16float> semantics if half precision must be preserved.
  4. If a scalar/vector template type still triggers this, inspect what the template TypeName resolved to — an unresolved alias may be mapping to a non-vector SymbolType.

Example fix

// before
Buffer<MyStruct> data; // NotSupportedException

// after
StructuredBuffer<MyStruct> data;
Defensive patterns

Strategy: type-guard

Validate before calling

static bool IsValidBufferTemplate(SymbolType? t) =>
    t is null or VectorType or ScalarType; // scalar/vector (half is auto-widened); null defaults to float4
if (!IsValidBufferTemplate(templateTypeName?.Type))
    throw new NotSupportedException("Typed Buffer<T> requires a scalar or vector T; use StructuredBuffer<T> otherwise");

Type guard

bool IsScalarOrVector(SymbolType t) => t is VectorType or ScalarType;

Try / catch

try
{
    SymbolTypes.TryGetBufferType(name, templateTypeName, out var sym);
}
catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported template type"))
{
    logger.LogError("Buffer '{Name}' templated on a composite type; rewrite as StructuredBuffer", name);
    throw;
}

Prevention

When it happens

Trigger: Declaring/parsing 'Buffer<T>' or 'RWBuffer<T>' where T resolves to a non-scalar/non-vector type — e.g. Buffer<MyStruct>, Buffer<float4x4>, Buffer<SomeMatrix>, or a custom UDT. (StructuredBuffer/RWStructuredBuffer/Append/ConsumeStructuredBuffer are exempt and accept arbitrary types.)

Common situations: Porting HLSL code that (illegally per FXC rules too, or permissively accepted elsewhere) templates a typed buffer with a struct or matrix; authoring new shader code assuming Buffer behaves like StructuredBuffer; a preceding parse failure leaving templateTypeName resolved to a composite type.

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/8c0402bfe64ecf99. Report an issue: GitHub.

Appendix: source

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

            case "ConsumeStructuredBuffer":
                result = new ConsumeStructuredBufferType(templateTypeName!.Type!);
                return true;
        }

        // Note: templateTypeName is resolved lazily (because it might not be a buffer type and we don't need to resolve it)

        // Preserves the full vector/scalar type (e.g. float2 stays float2). Defaults to float4 when no template given (HLSL default).
        static SymbolType ResolveReturnType(TypeName? templateTypeName)
            => WidenImageElementType(templateTypeName == null ? new VectorType(ScalarType.Float, 4) : templateTypeName.Type!);

        // Typed buffers only allow scalar/vector element types.
        static SymbolType ResolveBufferReturnType(TypeName? templateTypeName)
        {
            var templateType = WidenImageElementType(templateTypeName?.Type ?? new VectorType(ScalarType.Float, 4));
            return templateType switch
            {
                VectorType or ScalarType => templateType,
                _ => throw new NotSupportedException($"Unsupported template type {templateType} for Buffer"),
            };
        }

        // Vulkan requires an image's sampled type to be 32-bit int, 64-bit int or 32-bit float
        // (VUID-StandaloneSpirv-OpTypeImage-04656). The 16 bits live in the pixel format, so
        // widening the element type loses nothing.
        static SymbolType WidenImageElementType(SymbolType elementType) => elementType switch
        {
            ScalarType { Type: Scalar.Half } => ScalarType.Float,
            VectorType { BaseType: ScalarType { Type: Scalar.Half }, Size: var size } => new VectorType(ScalarType.Float, size),
            _ => elementType,
        };

        SymbolType? foundType = name switch
        {
            "Buffer" => new BufferType(ResolveBufferReturnType(templateTypeName)),
            "RWBuffer" => new BufferType(ResolveBufferReturnType(templateTypeName), true),

View on GitHub (pinned to 96fad776d2)