Comfy-Org/ComfyUI · error · ValueError

File3DToSplat: could not determine splat format from content

Error message

File3DToSplat: could not determine splat format from contents

What it means

Raised by _detect_splat_format when the input bytes match none of the four known signatures: 'ply' magic, gzip magic (\x1f\x8b), a ksplat 0.x header (byte0 == 0, byte1 >= 1), or a length divisible by 32 (antimatter15 .splat). File3DToSplat sniffs content rather than trusting the extension, so this means the payload is not recognizable as any supported splat format.

Source

Thrown at comfy_extras/nodes_gaussian_splat.py:406

        w = np.sqrt(np.clip(1.0 - (xq ** 2).sum(1), 0, None))
        rot = _norm_quat(np.concatenate([w[:, None], xq], 1))                    # wxyz
    return xyz, scale, rot, alpha, _rgb_to_sh_dc(rgb)


_GAUSSIAN_PARSERS = {"ply": _parse_ply_gaussian, "splat": _parse_splat_gaussian,
                     "ksplat": _parse_ksplat_gaussian, "spz": _parse_spz_gaussian}


def _detect_splat_format(data: bytes) -> str:
    if data[:3] == b'ply':
        return "ply"
    if data[:2] == b'\x1f\x8b':            # gzip -> spz
        return "spz"
    if len(data) >= 2 and data[0] == 0 and data[1] >= 1:   # ksplat version 0.x header
        return "ksplat"
    if len(data) % 32 == 0:
        return "splat"
    raise ValueError("File3DToSplat: could not determine splat format from contents")


def _gaussian_item(g: Types.SPLAT, i: int, device):
    # Slice batch item i to its real length, as float32 torch tensors on `device` (SH DC -> base RGB).
    end = _real_len(g, i)
    to = lambda a: a.to(device=device, dtype=torch.float32)
    xyz = to(g.positions[i, :end])
    rgb = (to(g.sh[i, :end, 0, :]) * _C0 + 0.5).clamp(0, 1)
    opacity = to(g.opacities[i, :end]).reshape(-1)
    scale = to(g.scales[i, :end])
    rot = to(g.rotations[i, :end])
    return xyz, rgb, opacity, scale, rot


def _quat_to_mat(q):
    # q: (N, 4) wxyz, normalized -> (N, 3, 3)
    q = q / q.norm(dim=-1, keepdim=True).clamp_min(1e-12)
    w, x, y, z = q.unbind(-1)

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Confirm the file is one of: PLY (binary_little_endian 3DGS), antimatter15 .splat, mkkellogg .ksplat v0.x, or Niantic .spz.
  2. Re-download/regenerate the file; verify magic bytes with a hex editor (70 6c 79 / 1f 8b / 00 xx).
  3. Convert the asset from its source format to one of the supported ones before loading.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

def sniff_splat_format(data: bytes):
    if data[:3] == b'ply':
        return 'ply'
    if data[:2] == b'\x1f\x8b':
        return 'spz'
    if len(data) >= 2 and data[0] == 0 and data[1] >= 1:
        return 'ksplat'
    if len(data) % 32 == 0:
        return 'splat'
    return None

fmt = sniff_splat_format(open(path, 'rb').read())
if fmt is None:
    raise ValueError(f'{path} is not a recognized splat format')

Type guard

def is_supported_splat_file(data: bytes) -> bool:
    return sniff_splat_format(data) is not None

Try / catch

try:
    fmt = _detect_splat_format(data)
except ValueError as e:
    if 'could not determine' in str(e):
        convert_asset_from_source(path)
    else:
        raise

Prevention

When it happens

Trigger: File3DToSplat on an arbitrary binary, a non-splat 3D format (obj/glb/las), an empty-ish or misaligned file whose length is not a multiple of 32, or a corrupted splat whose magic bytes were damaged.

Common situations: Wrong file connected to the node; a model file from another pipeline; corrupt download that lost its magic bytes; a .splat truncated so the length no longer divides by 32.

Related errors


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