{"record":{"id":"e69c41f2a6e21018","repo":"Comfy-Org/ComfyUI","slug":"file3dtosplat-invalid-spz-bad-magic","errorCode":null,"errorMessage":"File3DToSplat: invalid .spz (bad magic)","messagePattern":"File3DToSplat: invalid \\.spz \\(bad magic\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_extras/nodes_gaussian_splat.py","lineNumber":341,"sourceCode":"                nf = min(full_splats, cnt)\n                idx[:nf] = np.arange(nf) // bucket_size\n                if cnt > full_splats:\n                    lengths = np.frombuffer(data, '<u4', count=partial_buckets, offset=base)\n                    idx[full_splats:] = np.repeat(full_buckets + np.arange(partial_buckets), lengths)[:cnt - full_splats]\n                xyz = (rec['center'].astype(np.float32) - scale_range) * (block_size / 2.0 / scale_range) + buckets[idx]\n            parts.append((xyz, scale, rot, colf[:, 3].copy(), _rgb_to_sh_dc(colf[:, :3])))\n        base += bytes_per_splat * sec_max + buckets_store\n\n    if not parts:\n        raise ValueError(\"File3DToSplat: .ksplat has no splats\")\n    return tuple(np.concatenate([p[i] for p in parts]) for i in range(5))\n\n\ndef _parse_spz_gaussian(data: bytes):\n    # Niantic .spz (gzip-wrapped), versions 1-3. Base color only (SH skipped). See spark's SpzReader.\n    raw = gzip.decompress(data)\n    if struct.unpack_from('<I', raw, 0)[0] != _SPZ_MAGIC:\n        raise ValueError(\"File3DToSplat: invalid .spz (bad magic)\")\n    version = struct.unpack_from('<I', raw, 4)[0]\n    n = struct.unpack_from('<I', raw, 8)[0]\n    frac_bits = raw[13]\n    off = 16\n\n    if version == 1:\n        xyz = np.frombuffer(raw, '<f2', count=n * 3, offset=off).astype(np.float32).reshape(n, 3)\n        off += n * 6\n    elif version in (2, 3):\n        b = np.frombuffer(raw, np.uint8, count=n * 9, offset=off).reshape(n, 3, 3).astype(np.int64)\n        v = (b[..., 2] << 16) | (b[..., 1] << 8) | b[..., 0]\n        v = np.where(v & 0x800000, v - 0x1000000, v)                             # sign-extend 24-bit\n        xyz = (v / (1 << frac_bits)).astype(np.float32)\n        off += n * 9\n    else:\n        raise ValueError(f\"File3DToSplat: unsupported .spz version {version}\")\n\n    alpha = np.frombuffer(raw, np.uint8, count=n, offset=off).astype(np.float32) / 255.0","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_extras/nodes_gaussian_splat.py#L323-L359","documentation":"Raised by _parse_spz_gaussian when the gzip-decompressed payload does not start with the expected .spz magic constant. _detect_splat_format routes any gzip file (\\x1f\\x8b) to the spz parser, so this error means the file is gzip but not an .spz once decompressed. Effectively a corrupted .spz or a different gzipped format.","triggerScenarios":"File3DToSplat on a random .gz / gzipped non-spz file (any gzip stream matches the detection heuristic), or an .spz whose decompressed header is corrupted so the magic integer mismatches.","commonSituations":"Feeding a .gz archive or gzipped PLY to the node; a partially corrupted .spz transfer; renaming other files to .spz.","solutions":["Confirm the file is a genuine Niantic-format .spz (e.g., open it in a viewer that supports spz).","If it is another gzipped format, gunzip it first and load the inner format directly.","Re-download the .spz if corruption is suspected."],"exampleFix":"null","handlingStrategy":"validation","validationCode":"import gzip, struct\ndata = open(path, 'rb').read()\nif data[:2] == b'\\x1f\\x8b':\n    raw = gzip.decompress(data)\n    if struct.unpack_from('<I', raw, 0)[0] != 0x5053474e:  # _SPZ_MAGIC value per repo\n        raise ValueError(f'{path} is gzip but not spz')","typeGuard":"def is_spz(data: bytes) -> bool:\n    if data[:2] != b'\\x1f\\x8b':\n        return False\n    try:\n        raw = gzip.decompress(data)\n    except OSError:\n        return False\n    return len(raw) >= 4 and struct.unpack_from('<I', raw, 0)[0] == _SPZ_MAGIC","tryCatchPattern":"try:\n    result = _parse_spz_gaussian(data)\nexcept ValueError as e:\n    if 'bad magic' in str(e):\n        gunzip_and_inspect(path)  # probably another gzipped format\n    else:\n        raise","preventionTips":["Do not feed arbitrary .gz files; the detector maps every gzip stream to the spz parser.","Keep spz assets from trusted exporters and verify they open in an spz viewer."],"tags":["gaussian-splatting","spz","corrupt-file","file-format"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}