BabylonJS/Babylon.js · critical · Error
Invalid quaternion mode
Error message
Invalid quaternion mode
What it means
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).
Source
Thrown at packages/dev/loaders/src/SPLAT/sog.pure.ts:289
const d = Math.sqrt(Math.max(0, 1 - t));
// Place components according to mode
let q: [number, number, number, number];
switch (mode) {
case 0:
q = [d, a, b, c];
break; // omitted = x
case 1:
q = [a, d, b, c];
break; // omitted = y
case 2:
q = [a, b, d, c];
break; // omitted = z
case 3:
q = [a, b, c, d];
break; // omitted = w
default:
throw new Error("Invalid quaternion mode");
}
rot[i * 32 + 28 + 0] = q[0] * 127.5 + 127.5;
rot[i * 32 + 28 + 1] = q[1] * 127.5 + 127.5;
rot[i * 32 + 28 + 2] = q[2] * 127.5 + 127.5;
rot[i * 32 + 28 + 3] = q[3] * 127.5 + 127.5;
}
// --- SH
if (data.shN) {
const coeffs = data.shN.bands ? (data.shN.bands + 1) ** 2 - 1 : data.shN.shape[1] / 3; // 3 components per coeff
const shDegree = data.shN.bands !== undefined && data.shN.bands !== null ? data.shN.bands : Math.round(Math.sqrt(coeffs + 1) - 1);
const shCentroids = imageDataArrays[5].bits;
const shLabelsData = imageDataArrays[6].bits;
const shCentroidsWidth = imageDataArrays[5].width;
const shComponentCount = coeffs * 3;
View on GitHub (pinned to 0592b347b8)
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.
Example fix
// before (encoder wrote raw quaternion component) quats[i * 4 + 3] = Math.round(w * 127.5 + 127.5); // after (encoder packs the omitted-component mode) quats[i * 4 + 3] = 252 + omittedComponentIndex; // 252..255
Defensive patterns
Strategy: validation
Validate before calling
function validateQuatModes(quatsBits, splatCount) {
for (let i = 0; i < splatCount; i++) {
const modeByte = quatsBits[i * 4 + 3];
if (modeByte < 252 || modeByte > 255) {
throw new Error(`quats byte ${i * 4 + 3} = ${modeByte}; expected 252..255 (mode channel)`);
}
}
} Type guard
function hasValidQuatModeBytes(quatsBits, splatCount) {
return Array.from({ length: Math.min(splatCount, 64) }, (_, i) => quatsBits[i * 4 + 3])
.every((b) => b >= 252 && b <= 255);
} Try / catch
try {
return await ParseSogMeta(metaOrFiles, rootUrl, scene);
} catch (e) {
if (e.message === 'Invalid quaternion mode') {
// quats webp is corrupt or from an incompatible encoder: re-export the asset
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Missing codebook in SOG version 2 scales data.
- Missing arrays in SOG scales data.
- Missing codebook in SOG version 2 sh0 data.
- Missing arrays in SOG sh0 data.
- Missing codebook in SOG version 2 shN data.
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/26e3e0dcdc5b87b4.
Report an issue: GitHub.