{"record":{"id":"db86f833ed861ce6","repo":"BabylonJS/Babylon.js","slug":"gaussian-splat-data-byte-length-bytes-bytelengt","errorCode":null,"errorMessage":"Gaussian splat data byte length (${bytes.byteLength}) is not divisible by ${floatSize} and cannot be reinterpreted as Float32 data.","messagePattern":"Gaussian splat data byte length \\((.+?)\\) is not divisible by (.+?) and cannot be reinterpreted as Float32 data\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.ts","lineNumber":643,"sourceCode":"     * @returns A Uint8Array covering the exact source byte range.\n     * @internal\n     */\n    protected static _GetSplatDataBytes(data: ArrayBuffer | ArrayBufferView): Uint8Array {\n        return ArrayBuffer.isView(data) ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : new Uint8Array(data);\n    }\n\n    /**\n     * Returns a Float32 reinterpretation for retained splat data, copying only when alignment requires it.\n     * @param data The retained splat source bytes.\n     * @returns A Float32Array over the exact source byte range.\n     * @internal\n     */\n    protected static _GetSplatDataFloats(data: ArrayBuffer | ArrayBufferView): Float32Array {\n        const bytes = GaussianSplattingMeshBase._GetSplatDataBytes(data);\n        const floatSize = Float32Array.BYTES_PER_ELEMENT;\n\n        if (bytes.byteLength % floatSize !== 0) {\n            throw new Error(`Gaussian splat data byte length (${bytes.byteLength}) is not divisible by ${floatSize} and cannot be reinterpreted as Float32 data.`);\n        }\n\n        if (bytes.byteOffset % floatSize !== 0) {\n            const copy = new Uint8Array(bytes.byteLength);\n            copy.set(bytes);\n            return new Float32Array(copy.buffer, 0, bytes.byteLength / floatSize);\n        }\n\n        return new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / floatSize);\n    }\n\n    private static _BuildSplatRangeData(\n        ranges: Nullable<readonly IGaussianSplattingSplatRange[]>,\n        vertexCount: number\n    ): { ranges: Nullable<Uint32Array>; count: number; key: string } {\n        if (ranges === null) {\n            return { ranges: null, count: vertexCount, key: \"\" };\n        }","sourceCodeStart":625,"sourceCodeEnd":661,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.ts#L625-L661","documentation":"_GetSplatDataFloats reinterprets raw splat bytes as a Float32Array; it throws when the byte length is not a multiple of 4 (Float32Array.BYTES_PER_ELEMENT), since such data cannot be viewed as floats. This catches truncated or misaligned splat files early instead of producing garbage geometry.","triggerScenarios":"Loading a .splat/.ksplat file that was truncated during download, or passing a byte buffer containing a non-float layout (e.g. half-float or quantized data).","commonSituations":"Incomplete network fetch of splat assets stored in ArrayBuffer; hand-rolled binary splat writers emitting odd trailing bytes.","solutions":["Verify the downloaded asset length matches the expected splat count * 32 (or format stride) before passing it to the mesh","Trim or pad the buffer to a multiple of 4 bytes if the trailing bytes are known junk","Re-download the file if truncated"],"exampleFix":"// before\nmesh.setData(buffer); // buffer.byteLength % 4 !== 0\n// after\nif (buffer.byteLength % 4 !== 0) {\n    buffer = buffer.slice(0, buffer.byteLength - (buffer.byteLength % 4));\n}\nmesh.setData(buffer);","handlingStrategy":"validation","validationCode":"if ((data.byteLength ?? data.buffer.byteLength) % 4 !== 0) {\n  throw new RangeError('splat buffer not 4-byte aligned in length');\n}","typeGuard":"function isFloat32Reinterpretable(data: ArrayBuffer | ArrayBufferView): data is ArrayBuffer | ArrayBufferView {\n  return (ArrayBuffer.isView(data) ? data.byteLength : data.byteLength) % Float32Array.BYTES_PER_ELEMENT === 0;\n}","tryCatchPattern":"try {\n  mesh.setData(buffer);\n} catch (e) {\n  if (String(e).includes('not divisible by')) { reDownloadOrTrim(buffer); }\n  else throw e;\n}","preventionTips":["Verify downloaded splat asset sizes against the manifest before use","Pad/truncate buffers to 4-byte multiples at load boundaries","Check completeness of streamed/fetched binary assets"],"tags":["gaussian-splatting","binary-data","validation"],"backgroundTag":"byte-length-not-aligned","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}