{"record":{"id":"8c0402bfe64ecf99","repo":"stride3d/stride","slug":"unsupported-template-type-templatetype-for-buffer","errorCode":null,"errorMessage":"Unsupported template type {templateType} for Buffer","messagePattern":"Unsupported template type (.+?) for Buffer","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Core/SymbolTypes.cs","lineNumber":81,"sourceCode":"            case \"ConsumeStructuredBuffer\":\n                result = new ConsumeStructuredBufferType(templateTypeName!.Type!);\n                return true;\n        }\n\n        // Note: templateTypeName is resolved lazily (because it might not be a buffer type and we don't need to resolve it)\n\n        // Preserves the full vector/scalar type (e.g. float2 stays float2). Defaults to float4 when no template given (HLSL default).\n        static SymbolType ResolveReturnType(TypeName? templateTypeName)\n            => WidenImageElementType(templateTypeName == null ? new VectorType(ScalarType.Float, 4) : templateTypeName.Type!);\n\n        // Typed buffers only allow scalar/vector element types.\n        static SymbolType ResolveBufferReturnType(TypeName? templateTypeName)\n        {\n            var templateType = WidenImageElementType(templateTypeName?.Type ?? new VectorType(ScalarType.Float, 4));\n            return templateType switch\n            {\n                VectorType or ScalarType => templateType,\n                _ => throw new NotSupportedException($\"Unsupported template type {templateType} for Buffer\"),\n            };\n        }\n\n        // Vulkan requires an image's sampled type to be 32-bit int, 64-bit int or 32-bit float\n        // (VUID-StandaloneSpirv-OpTypeImage-04656). The 16 bits live in the pixel format, so\n        // widening the element type loses nothing.\n        static SymbolType WidenImageElementType(SymbolType elementType) => elementType switch\n        {\n            ScalarType { Type: Scalar.Half } => ScalarType.Float,\n            VectorType { BaseType: ScalarType { Type: Scalar.Half }, Size: var size } => new VectorType(ScalarType.Float, size),\n            _ => elementType,\n        };\n\n        SymbolType? foundType = name switch\n        {\n            \"Buffer\" => new BufferType(ResolveBufferReturnType(templateTypeName)),\n            \"RWBuffer\" => new BufferType(ResolveBufferReturnType(templateTypeName), true),\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Core/SymbolTypes.cs#L63-L99","documentation":"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').","triggerScenarios":"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.)","commonSituations":"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.","solutions":["Use StructuredBuffer<T> / RWStructuredBuffer<T> instead of Buffer<T> for struct, matrix, or other composite element types.","Keep the typed buffer's template restricted to scalar (float, int, uint) or vector (float2/3/4, int4, ...) types.","If half-based elements are intended, note they are widened to float; use StructuredBuffer<min16float> semantics if half precision must be preserved.","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."],"exampleFix":"// before\nBuffer<MyStruct> data; // NotSupportedException\n\n// after\nStructuredBuffer<MyStruct> data;","handlingStrategy":"type-guard","validationCode":"static bool IsValidBufferTemplate(SymbolType? t) =>\n    t is null or VectorType or ScalarType; // scalar/vector (half is auto-widened); null defaults to float4\nif (!IsValidBufferTemplate(templateTypeName?.Type))\n    throw new NotSupportedException(\"Typed Buffer<T> requires a scalar or vector T; use StructuredBuffer<T> otherwise\");","typeGuard":"bool IsScalarOrVector(SymbolType t) => t is VectorType or ScalarType;","tryCatchPattern":"try\n{\n    SymbolTypes.TryGetBufferType(name, templateTypeName, out var sym);\n}\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"Unsupported template type\"))\n{\n    logger.LogError(\"Buffer '{Name}' templated on a composite type; rewrite as StructuredBuffer\", name);\n    throw;\n}","preventionTips":["Reserve Buffer/RWBuffer for scalar and vector element types; use StructuredBuffer for structs and matrices.","Add a shader-authoring lint that flags Buffer<T> where T is not a scalar/vector.","Remember half templates are widened to float — don't rely on Buffer<half> keeping 16-bit precision.","Cover typical buffer templates (float, float4, int, uint, and one struct case) in parser tests."],"tags":["shader-parsing","buffers","type-mismatch","not-supported"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}