{"record":{"id":"2c4241959ac65a4a","repo":"stride3d/stride","slug":"size-of-t-is-not-a-multiple-of-totalsize-0","errorCode":null,"errorMessage":"Size of T is not a multiple of totalSize {0}","messagePattern":"Size of T is not a multiple of totalSize (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Rendering/Extensions/VertexExtensions.cs","lineNumber":35,"sourceCode":"        /// </summary>\n        /// <param name=\"meshData\">The mesh data.</param>\n        /// <param name=\"vertexElementToExtract\">The declaration to extract (e.g. \"POSITION0\"...etc.) </param>\n        [Obsolete($\"Use {nameof(VertexBufferHelper)} instead\")]\n        public static unsafe T[] GetVertexBufferData<T>(this MeshDraw meshData, params string[] vertexElementToExtract) where T : unmanaged\n        {\n            var declaration = meshData.VertexBuffers[0].Declaration;\n\n            var offsets = declaration.EnumerateWithOffsets().Where(vertexElementOffset => vertexElementToExtract.Contains(vertexElementOffset.VertexElement.SemanticAsText)).ToList();\n\n            int expectedSize = offsets.Sum(vertexElementWithOffset => vertexElementWithOffset.Size);\n\n            var count = meshData.VertexBuffers[0].Count;\n\n            int outputSize = expectedSize * count;\n\n            int checkSize = (int)(outputSize / Unsafe.SizeOf<T>()) * Unsafe.SizeOf<T>();\n            if (checkSize != outputSize)\n                throw new ArgumentException(string.Format(\"Size of T is not a multiple of totalSize {0}\", outputSize));\n\n            var output = new T[outputSize / Unsafe.SizeOf<T>()];\n\n            fixed (T* ptrOutputT = output)\n            fixed (byte* ptrInputStart = meshData.VertexBuffers[0].Buffer.GetSerializationData().Content) {\n                var ptrOutput = (byte*)ptrOutputT;\n                var ptrInput = ptrInputStart;\n                for (int i = 0; i < count; i++)\n                {\n                    foreach (var vertexElementWithOffset in offsets)\n                    {\n                        MemoryUtilities.CopyWithAlignmentFallback(ptrOutput, ptrInput + vertexElementWithOffset.Offset, (uint)vertexElementWithOffset.Size);\n                        ptrOutput += vertexElementWithOffset.Size;\n                    }\n                    ptrInput += declaration.VertexStride;\n                }\n            }\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Rendering/Extensions/VertexExtensions.cs#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nvar data = mesh.GetVertexBufferData<MyPackedVertex>(); // stride 24, sizeof(MyPackedVertex)=28\n// after\n[StructLayout(LayoutKind.Sequential)]\nstruct MyPackedVertex { public Vector3 Pos; public Vector3 Normal; } // 24 bytes, matches stride\nvar data = mesh.GetVertexBufferData<MyPackedVertex>();","handlingStrategy":"validation","validationCode":"int expectedSize = mesh.VertexBuffers[0].Declaration.VertexStride;\nint count = mesh.VertexBuffers[0].Count;\nint outputSize = expectedSize * count;\nif (outputSize % Unsafe.SizeOf<T>() != 0)\n    throw new InvalidOperationException($\"T (sizeof {Unsafe.SizeOf<T>()}) does not divide {outputSize} bytes\");","typeGuard":"static bool CanReadAs<T>(MeshDraw mesh) where T : unmanaged =>\n    (mesh.VertexBuffers[0].Declaration.VertexStride * mesh.VertexBuffers[0].Count)\n    % Unsafe.SizeOf<T>() == 0;","tryCatchPattern":"try { var data = mesh.GetVertexBufferData<T>(); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Size of T is not a multiple\")) {\n    // fix the struct layout / declaration stride, or read as byte[] and marshal\n}","preventionTips":["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"],"tags":["csharp","unsafe","vertex-data"],"backgroundTag":"type-mismatch","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"}