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
- Re-export the scene from the source tool with actual gaussians present.
- Verify the file size is well beyond 4096 + sections*1024 bytes (an empty-header file is suspiciously small).
- 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
- Sanity-check that exported ksplat files have a non-zero splat count.
- Reject suspiciously small ksplat files (header-only) at load time.
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
- File3DToSplat: unsupported .ksplat version {data[0]}.{data[1
- File3DToSplat: invalid .ksplat compression level {level}
- SplatToFile3D: gaussian is empty
- File3DToSplat: not a PLY (missing end_header)
- File3DToSplat: unsupported PLY format '{p[1]}' (need binary_
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/99c5d6b11c9d1a5a.
Report an issue: GitHub.