Comfy-Org/ComfyUI · error · ValueError

File3DToSplat: unsupported .spz version {version}

Error message

File3DToSplat: unsupported .spz version {version}

What it means

Raised by _parse_spz_gaussian when the version field of the decompressed .spz header is not 1, 2, or 3. Version 1 stores half-float positions, versions 2-3 use 24-bit fixed-point positions (v3 adds smallest-three quaternion encoding); anything else is a format generation the reader does not implement.

Source

Thrown at comfy_extras/nodes_gaussian_splat.py:357

    raw = gzip.decompress(data)
    if struct.unpack_from('<I', raw, 0)[0] != _SPZ_MAGIC:
        raise ValueError("File3DToSplat: invalid .spz (bad magic)")
    version = struct.unpack_from('<I', raw, 4)[0]
    n = struct.unpack_from('<I', raw, 8)[0]
    frac_bits = raw[13]
    off = 16

    if version == 1:
        xyz = np.frombuffer(raw, '<f2', count=n * 3, offset=off).astype(np.float32).reshape(n, 3)
        off += n * 6
    elif version in (2, 3):
        b = np.frombuffer(raw, np.uint8, count=n * 9, offset=off).reshape(n, 3, 3).astype(np.int64)
        v = (b[..., 2] << 16) | (b[..., 1] << 8) | b[..., 0]
        v = np.where(v & 0x800000, v - 0x1000000, v)                             # sign-extend 24-bit
        xyz = (v / (1 << frac_bits)).astype(np.float32)
        off += n * 9
    else:
        raise ValueError(f"File3DToSplat: unsupported .spz version {version}")

    alpha = np.frombuffer(raw, np.uint8, count=n, offset=off).astype(np.float32) / 255.0
    off += n
    cb = np.frombuffer(raw, np.uint8, count=n * 3, offset=off).reshape(n, 3).astype(np.float32)
    off += n * 3
    rgb = (cb / 255.0 - 0.5) * _SPZ_COLOR_SCALE + 0.5
    sb = np.frombuffer(raw, np.uint8, count=n * 3, offset=off).reshape(n, 3).astype(np.float32)
    off += n * 3
    scale = np.exp(sb / 16.0 - 10.0)

    if version == 3:                                                             # smallest-three quaternion
        qb = np.frombuffer(raw, np.uint8, count=n * 4, offset=off).reshape(n, 4).astype(np.int64)
        combined = qb[:, 0] | (qb[:, 1] << 8) | (qb[:, 2] << 16) | (qb[:, 3] << 24)
        largest = (combined >> 30) & 3
        q = np.zeros((n, 4), np.float32)                                         # x,y,z,w
        remaining, sumsq = combined.copy(), np.zeros(n, np.float64)
        for comp in (3, 2, 1, 0):
            active = comp != largest

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Re-export as .ply (universally supported) from the tool holding the original data.
  2. Check for a ComfyUI update that adds support for the newer spz version.
  3. Convert the spz with the official spz tooling down to a supported version if available.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

import gzip, struct
raw = gzip.decompress(open(path, 'rb').read())
version = struct.unpack_from('<I', raw, 4)[0]
if version not in (1, 2, 3):
    raise ValueError(f'spz version {version} unsupported; re-export as ply')

Type guard

def spz_version_supported(data: bytes) -> bool:
    raw = gzip.decompress(data)
    return struct.unpack_from('<I', raw, 4)[0] in (1, 2, 3)

Try / catch

try:
    result = _parse_spz_gaussian(data)
except ValueError as e:
    if 'unsupported .spz version' in str(e):
        re_export_as_ply(path)
    else:
        raise

Prevention

When it happens

Trigger: File3DToSplat on an .spz written by a newer spz spec revision (version >= 4) or a corrupted version field; the magic matched, so the file is structurally spz-like but of an unknown generation.

Common situations: Niantic/spz format evolution after this reader was written; byte-level header corruption; experimental writers using custom version numbers.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/d0bc1daf0faffbe2. Report an issue: GitHub.