Comfy-Org/ComfyUI · error · ValueError

File3DToSplat: .ksplat has no splats

Error message

File3DToSplat: .ksplat has no splats

What it means

Raised by _parse_ksplat_gaussian when after iterating all declared sections no section contributed any splats (parts list is empty). Every section either had a splat count of 0 or was skipped, so the file describes a valid header but contains zero gaussians. The parser refuses because concatenating zero parts would yield degenerate empty tensors.

Source

Thrown at comfy_extras/nodes_gaussian_splat.py:333

            rot = _norm_quat(rec['rot'].astype(np.float32))                       # wxyz
            scale = rec['scale'].astype(np.float32)
            if level == 0:
                xyz = rec['center'].astype(np.float32)
            else:
                buckets = np.frombuffer(data, '<f4', count=bucket_count * 3, offset=base + meta_bytes).reshape(-1, 3)
                idx = np.empty(cnt, np.int64)
                full_splats = full_buckets * bucket_size
                nf = min(full_splats, cnt)
                idx[:nf] = np.arange(nf) // bucket_size
                if cnt > full_splats:
                    lengths = np.frombuffer(data, '<u4', count=partial_buckets, offset=base)
                    idx[full_splats:] = np.repeat(full_buckets + np.arange(partial_buckets), lengths)[:cnt - full_splats]
                xyz = (rec['center'].astype(np.float32) - scale_range) * (block_size / 2.0 / scale_range) + buckets[idx]
            parts.append((xyz, scale, rot, colf[:, 3].copy(), _rgb_to_sh_dc(colf[:, :3])))
        base += bytes_per_splat * sec_max + buckets_store

    if not parts:
        raise ValueError("File3DToSplat: .ksplat has no splats")
    return tuple(np.concatenate([p[i] for p in parts]) for i in range(5))


def _parse_spz_gaussian(data: bytes):
    # Niantic .spz (gzip-wrapped), versions 1-3. Base color only (SH skipped). See spark's SpzReader.
    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)

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Re-export the scene from the source tool with actual gaussians present.
  2. Verify the file size is well beyond 4096 + sections*1024 bytes (an empty-header file is suspiciously small).
  3. Load the file in the viewer that produced it to confirm it shows splats.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

import struct
data = open(path, 'rb').read()
max_sections = struct.unpack_from('<I', data, 4)[0]
total = sum(struct.unpack_from('<I', data, 4096 + s * 1024)[0] for s in range(max_sections))
if total == 0:
    raise ValueError('ksplat contains zero splats; re-export the scene')

Try / catch

try:
    result = _parse_ksplat_gaussian(data)
except ValueError as e:
    if 'no splats' in str(e):
        re_export_nonempty_scene(path)
    else:
        raise

Prevention

When it happens

Trigger: File3DToSplat on a .ksplat whose header is well-formed but whose maxSections sections all report cnt == 0: an empty export, a header-only stub, or a file whose section data was stripped.

Common situations: Exporting an empty scene from a splat viewer; truncated file that kept the 4096-byte header but lost section payloads; testing with placeholder ksplat files.

Related errors


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