{"record":{"id":"26e3e0dcdc5b87b4","repo":"BabylonJS/Babylon.js","slug":"invalid-quaternion-mode","errorCode":null,"errorMessage":"Invalid quaternion mode","messagePattern":"Invalid quaternion mode","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/dev/loaders/src/SPLAT/sog.pure.ts","lineNumber":289,"sourceCode":"        const d = Math.sqrt(Math.max(0, 1 - t));\r\n\r\n        // Place components according to mode\r\n        let q: [number, number, number, number];\r\n        switch (mode) {\r\n            case 0:\r\n                q = [d, a, b, c];\r\n                break; // omitted = x\r\n            case 1:\r\n                q = [a, d, b, c];\r\n                break; // omitted = y\r\n            case 2:\r\n                q = [a, b, d, c];\r\n                break; // omitted = z\r\n            case 3:\r\n                q = [a, b, c, d];\r\n                break; // omitted = w\r\n            default:\r\n                throw new Error(\"Invalid quaternion mode\");\r\n        }\r\n\r\n        rot[i * 32 + 28 + 0] = q[0] * 127.5 + 127.5;\r\n        rot[i * 32 + 28 + 1] = q[1] * 127.5 + 127.5;\r\n        rot[i * 32 + 28 + 2] = q[2] * 127.5 + 127.5;\r\n        rot[i * 32 + 28 + 3] = q[3] * 127.5 + 127.5;\r\n    }\r\n\r\n    // --- SH\r\n    if (data.shN) {\r\n        const coeffs = data.shN.bands ? (data.shN.bands + 1) ** 2 - 1 : data.shN.shape[1] / 3; // 3 components per coeff\r\n        const shDegree = data.shN.bands !== undefined && data.shN.bands !== null ? data.shN.bands : Math.round(Math.sqrt(coeffs + 1) - 1);\r\n        const shCentroids = imageDataArrays[5].bits;\r\n        const shLabelsData = imageDataArrays[6].bits;\r\n        const shCentroidsWidth = imageDataArrays[5].width;\r\n\r\n        const shComponentCount = coeffs * 3;\r\n\r","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/loaders/src/SPLAT/sog.pure.ts#L271-L307","documentation":"SOG stores rotations as 3 quaternion components plus a 4th byte encoding which component is omitted (mode = 4th byte - 252, valid 0..3). This error means a splat's 4th rotation byte produced a mode outside 0-3, i.e. the quaternion image data is corrupt or not in the expected SOG encoding (bytes must be in 252..255 for the mode channel).","triggerScenarios":"Parsing a SOG bundle whose quats webp was produced by an incompatible encoder, re-encoded/re-compressed with lossy processing that changed byte 4, or where raw (non-252-offset) quaternion values were written instead of the packed mode representation.","commonSituations":"Third-party SOG files that store quaternions differently (e.g. full 4-component encoding); image pipeline re-compression or color-profile conversion altering pixel values; truncated/corrupted webp decode results.","solutions":["Re-export the SOG asset with the official SOG encoder so quats bytes use the 252+mode packing.","Check the quats webp was not re-compressed or color-converted after generation; keep it byte-exact (it is data, not a picture).","Sanity-check quats data before parsing: every 4th byte per splat must be 252..255."],"exampleFix":"// before (encoder wrote raw quaternion component)\nquats[i * 4 + 3] = Math.round(w * 127.5 + 127.5);\n// after (encoder packs the omitted-component mode)\nquats[i * 4 + 3] = 252 + omittedComponentIndex; // 252..255","handlingStrategy":"validation","validationCode":"function validateQuatModes(quatsBits, splatCount) {\n  for (let i = 0; i < splatCount; i++) {\n    const modeByte = quatsBits[i * 4 + 3];\n    if (modeByte < 252 || modeByte > 255) {\n      throw new Error(`quats byte ${i * 4 + 3} = ${modeByte}; expected 252..255 (mode channel)`);\n    }\n  }\n}","typeGuard":"function hasValidQuatModeBytes(quatsBits, splatCount) {\n  return Array.from({ length: Math.min(splatCount, 64) }, (_, i) => quatsBits[i * 4 + 3])\n    .every((b) => b >= 252 && b <= 255);\n}","tryCatchPattern":"try {\n  return await ParseSogMeta(metaOrFiles, rootUrl, scene);\n} catch (e) {\n  if (e.message === 'Invalid quaternion mode') {\n    // quats webp is corrupt or from an incompatible encoder: re-export the asset\n  }\n  throw e;\n}","preventionTips":["Serve SOG webp files byte-exact: disable image re-compression/optimization CDNs for them.","Spot-check the quats image bytes (4th channel in 252..255) after download, before parsing.","Only use SOG files produced by encoders matching the format spec the loader implements."],"tags":["sog","gaussian-splatting","quaternion","corrupt-data","asset-validation"],"backgroundTag":"corrupt-asset-data","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}