stride3d/stride · error · ArgumentException
Size of T is not a multiple of totalSize
Error message
Size of T is not a multiple of totalSize {0} What it means
GetVertexBufferData copies the mesh's raw vertex bytes into a T[] using unsafe pointers. The total byte size must be an exact multiple of sizeof(T); if the vertex data size is not divisible by T's size, the copy would lose or misinterpret bytes, so an ArgumentException with the total size is thrown.
Solutions
- Use a T whose size exactly matches the vertex declaration stride (declare struct fields to mirror the declaration, add missing fields/padding)
- Fix the vertex declaration so its stride matches sizeof(T) times the layout
- Read into byte[] and reinterpret/marshal manually instead of a fixed T
Example fix
// before
var data = mesh.GetVertexBufferData<MyPackedVertex>(); // stride 24, sizeof(MyPackedVertex)=28
// after
[StructLayout(LayoutKind.Sequential)]
struct MyPackedVertex { public Vector3 Pos; public Vector3 Normal; } // 24 bytes, matches stride
var data = mesh.GetVertexBufferData<MyPackedVertex>(); Defensive patterns
Strategy: validation
Validate before calling
int expectedSize = mesh.VertexBuffers[0].Declaration.VertexStride;
int count = mesh.VertexBuffers[0].Count;
int outputSize = expectedSize * count;
if (outputSize % Unsafe.SizeOf<T>() != 0)
throw new InvalidOperationException($"T (sizeof {Unsafe.SizeOf<T>()}) does not divide {outputSize} bytes"); Type guard
static bool CanReadAs<T>(MeshDraw mesh) where T : unmanaged =>
(mesh.VertexBuffers[0].Declaration.VertexStride * mesh.VertexBuffers[0].Count)
% Unsafe.SizeOf<T>() == 0; Try / catch
try { var data = mesh.GetVertexBufferData<T>(); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Size of T is not a multiple")) {
// fix the struct layout / declaration stride, or read as byte[] and marshal
} Prevention
- Mirror the vertex declaration exactly in your C# struct (fields, order, size)
- Use Marshal.SizeOf/Unsafe.SizeOf checks in tests against VertexStride
- Prefer byte-level reads plus explicit reinterpretation for exotic layouts
When it happens
Trigger: Calling GetVertexBufferData<T> where expectedSize * count is not a multiple of Unsafe.SizeOf<T>() — e.g. reading vertices as a struct whose stride differs from the vertex declaration stride, or T larger than the per-vertex size.
Common situations: Mismatch between the vertex declaration stride and the C# struct used for T; reading padding-containing structs against packed vertex data; querying float4 data into float3 structs or vice versa.
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
- A file path cannot end with with directory char '\' or '/'…
- A Gear constraint requires two rigidbodies.
- A MaterialPass can only belong to a single Material
- A routed event named
- Already scheduled, call Unschedule before running this…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/2c4241959ac65a4a.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Rendering/Extensions/VertexExtensions.cs:35
/// </summary>
/// <param name="meshData">The mesh data.</param>
/// <param name="vertexElementToExtract">The declaration to extract (e.g. "POSITION0"...etc.) </param>
[Obsolete($"Use {nameof(VertexBufferHelper)} instead")]
public static unsafe T[] GetVertexBufferData<T>(this MeshDraw meshData, params string[] vertexElementToExtract) where T : unmanaged
{
var declaration = meshData.VertexBuffers[0].Declaration;
var offsets = declaration.EnumerateWithOffsets().Where(vertexElementOffset => vertexElementToExtract.Contains(vertexElementOffset.VertexElement.SemanticAsText)).ToList();
int expectedSize = offsets.Sum(vertexElementWithOffset => vertexElementWithOffset.Size);
var count = meshData.VertexBuffers[0].Count;
int outputSize = expectedSize * count;
int checkSize = (int)(outputSize / Unsafe.SizeOf<T>()) * Unsafe.SizeOf<T>();
if (checkSize != outputSize)
throw new ArgumentException(string.Format("Size of T is not a multiple of totalSize {0}", outputSize));
var output = new T[outputSize / Unsafe.SizeOf<T>()];
fixed (T* ptrOutputT = output)
fixed (byte* ptrInputStart = meshData.VertexBuffers[0].Buffer.GetSerializationData().Content) {
var ptrOutput = (byte*)ptrOutputT;
var ptrInput = ptrInputStart;
for (int i = 0; i < count; i++)
{
foreach (var vertexElementWithOffset in offsets)
{
MemoryUtilities.CopyWithAlignmentFallback(ptrOutput, ptrInput + vertexElementWithOffset.Offset, (uint)vertexElementWithOffset.Size);
ptrOutput += vertexElementWithOffset.Size;
}
ptrInput += declaration.VertexStride;
}
}
View on GitHub (pinned to 96fad776d2)