{"record":{"id":"c79cb4954c9bef41","repo":"BabylonJS/Babylon.js","slug":"byte-stride-cannot-be-smaller-than-the-component-s","errorCode":null,"errorMessage":"Byte stride cannot be smaller than the component's byte size.","messagePattern":"Byte stride cannot be smaller than the component's byte size\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Buffers/bufferUtils.ts","lineNumber":361,"sourceCode":"    // Handle ArrayBuffer and ArrayBufferView\r\n    let buffer: ArrayBufferLike;\r\n    let adjustedByteOffset = byteOffset;\r\n\r\n    if (ArrayBuffer.isView(data)) {\r\n        buffer = data.buffer;\r\n        adjustedByteOffset += data.byteOffset;\r\n    } else {\r\n        buffer = data;\r\n    }\r\n\r\n    const lastByteOffset = adjustedByteOffset + (totalVertices - 1) * byteStride + size * typeByteLength;\r\n    if (lastByteOffset > buffer.byteLength) {\r\n        throw new Error(\"Last accessed byte is out of bounds.\");\r\n    }\r\n\r\n    const tightlyPackedByteStride = size * typeByteLength;\r\n    if (byteStride < tightlyPackedByteStride) {\r\n        throw new Error(\"Byte stride cannot be smaller than the component's byte size.\");\r\n    }\r\n    if (byteStride !== tightlyPackedByteStride) {\r\n        const copy = new constructor(count);\r\n        const src = new Uint8Array(buffer, adjustedByteOffset);\r\n        const dst = new Uint8Array(copy.buffer);\r\n        const rowBytes = size * typeByteLength;\r\n        for (let v = 0, s = 0, d = 0; v < totalVertices; v++, s += byteStride, d += rowBytes) {\r\n            dst.set(src.subarray(s, s + rowBytes), d);\r\n        }\r\n        return copy;\r\n    }\r\n\r\n    if (typeByteLength !== 1 && (adjustedByteOffset & (typeByteLength - 1)) !== 0) {\r\n        Logger.Warn(\"Array must be aligned to border of element size. Data will be copied.\");\r\n        forceCopy = true;\r\n    }\r\n\r\n    if (forceCopy) {\r","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Buffers/bufferUtils.ts#L343-L379","documentation":"BufferUtils.GetTypedArrayData throws when the caller-supplied byteStride is smaller than size * typeByteLength (the bytes one tightly-packed row of `size` components actually needs). A stride smaller than a row would make rows overlap, which typed array views over the buffer cannot represent, so the library refuses instead of producing corrupt data.","triggerScenarios":"Calling GetTypedArrayData (directly or via VertexBuffer.data/typedData/typedArray) with a byteStride value manually computed as e.g. (size-1)*4 or copied from a stride meant for a different attribute/type; passing a stride of 0 while size > 1 or a mismatched typeByteLength (e.g. reading FLOAT data with a DOUBLE-sized type constant).","commonSituations":"Importing glTF/obj data with hand-rolled stride math; reading interleaved vertex buffers where the stride was computed for one attribute but reused for another; changing `size` (components per vertex) without updating byteStride.","solutions":["Set byteStride >= size * typeByteLength; if data is tightly packed pass exactly size * typeByteLength (or the same value used to create the buffer).","Recompute stride from the actual type: GetTypeByteLength(type) * size.","If reading an interleaved buffer, use the stride of the whole vertex layout, which must be larger than the per-attribute stride.","Pass undefined/null byteStride where the API allows so it defaults to tightly packed."],"exampleFix":"// before\nconst data = vertexBuffer.typedData; // internally byteStride = 8, size = 4, FLOAT (16 needed)\n\n// after\nconst byteStride = 4 * 4; // size * GetTypeByteLength(Constants.FLOAT)\nconst data = vertexBuffer.getTypedData(0, 1 /* vertices */, byteStride); // or fix the layout stride to >= 16","handlingStrategy":"validation","validationCode":"const typeByteLength = vertexBuffer.getTypeByteLength?.() ?? 4; // FLOAT\nconst minStride = size * typeByteLength;\nif (byteStride !== undefined && byteStride < minStride) {\n  throw new RangeError(`byteStride ${byteStride} < required ${minStride}`);\n}\nconst data = vertexBuffer.getTypedData(vertexStart, vertexCount, Math.max(byteStride, minStride));","typeGuard":"function hasValidStride(size, typeByteLength, byteStride) {\n  return byteStride === undefined || byteStride >= size * typeByteLength;\n}","tryCatchPattern":"let data;\ntry {\n  data = vertexBuffer.typedData;\n} catch (e) {\n  if (/Byte stride/.test(e.message)) {\n    data = vertexBuffer.getTypedData(0, vertexBuffer.getTotalVertices(), size * 4);\n  } else throw e;\n}","preventionTips":["Compute strides as size * GetTypeByteLength(type), never hardcode byte counts.","Use one shared vertex-layout definition so attribute sizes and strides stay in sync.","Prefer tightly packed (undefined) stride unless data is genuinely interleaved.","Validate imported (glTF) accessors' byteStride before reading."],"tags":["buffers","typedarray","vertex-data","babylonjs"],"backgroundTag":"invalid-buffer-stride","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}