stride3d/stride · error · NotImplementedException

Unsupported format when converting vertex element

Error message

Unsupported format when converting vertex element ({format})

What it means

This is the interleaved-copy path of VertexBufferHelper: it dispatches on the element's PixelFormat to choose a typed InterleavedCopy<T,...> instantiation. Only R32G32B32A32_Float, R16G16_Float, R16G16B16A16_Float, R16G16B16A16_UInt, R8G8B8A8_UInt and R8G8B8A8_UNorm are handled; any other format falls through to default and throws NotImplementedException. The library refuses to guess how to convert an unknown pixel layout.

Solutions

  1. Change the vertex declaration to use a supported PixelFormat for that element
  2. Pre-convert the vertex data into one of the six supported formats before conversion
  3. Add a case to the format switch that calls InterleavedCopy with an appropriate unmanaged source type
  4. Log elementData format values when the error occurs to know exactly which one to add or convert

Example fix

// before
new VertexElement("POSITION", 0, PixelFormat.R32G32B32_Float, 0) // throws
// after
new VertexElement("POSITION", 0, PixelFormat.R32G32B32A32_Float, 0) // supported
Defensive patterns

Strategy: validation

Validate before calling

if (!supportedFormats.Contains(elementFormat))
    throw new InvalidOperationException($"Interleaved conversion unsupported for {elementFormat}");

Try / catch

try { ConvertInterleaved(param); }
catch (NotImplementedException ex) { logger.Error(ex, "Unsupported interleaved vertex format"); throw; }

Prevention

When it happens

Trigger: Calling the interleaved vertex conversion API (Convert with interleaved parameters) where the source vertex element's format is not one of the six supported PixelFormats, e.g. R32G32B32_Float or R8G8_UNorm.

Common situations: Mesh assets exported with compact or snorm formats from other tools; changing vertex compression settings in the pipeline; using a custom vertex declaration whose format differs from Stride's defaults.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/VertexBufferHelper.cs:176

            IConverter<Half2, TOutput>,
            IConverter<Half4, TOutput>,
            IConverter<UShort4, TOutput>,
            IConverter<Byte4, TOutput>,
            IConverter<Color, TOutput>,
            ISemantic
            where TOutput : unmanaged
        {
            switch (format)
            {
                case PixelFormat.R32G32_Float: InterleavedCopy<TSemantic, Vector2, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R32G32B32_Float: InterleavedCopy<TSemantic, Vector3, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R32G32B32A32_Float: InterleavedCopy<TSemantic, Vector4, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R16G16_Float: InterleavedCopy<TSemantic, Half2, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R16G16B16A16_Float: InterleavedCopy<TSemantic, Half4, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R16G16B16A16_UInt: InterleavedCopy<TSemantic, UShort4, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R8G8B8A8_UInt: InterleavedCopy<TSemantic, Byte4, TOutput>(param, srcElemOffset, destElemOffset); break;
                case PixelFormat.R8G8B8A8_UNorm: InterleavedCopy<TSemantic, Color, TOutput>(param, srcElemOffset, destElemOffset); break;
                default: throw new NotImplementedException($"Unsupported format when converting vertex element ({format})");
            }
        }
        
        static void InterleavedCopy<TConverter, TSourceSemVal, TDestSemVal>(InterleavedParameters param, int srcElemOffset, int destElemOffset) 
            where TConverter : IConverter<TSourceSemVal, TDestSemVal> 
            where TSourceSemVal : unmanaged
            where TDestSemVal : unmanaged
        {
            fixed (byte* srcStart = param.Source)
            fixed (byte* destStart = param.Destination)
            {
                for (byte* 
                     src = srcStart + srcElemOffset,
                     dest = destStart + destElemOffset,
                     endSrc = src + param.VertexCount * param.SourceStride;
                     
                     src < endSrc;
                     

View on GitHub (pinned to 96fad776d2)