{"record":{"id":"9638f0986b3f61f3","repo":"Comfy-Org/ComfyUI","slug":"file3dtosplat-not-a-ply-missing-end-header","errorCode":null,"errorMessage":"File3DToSplat: not a PLY (missing end_header)","messagePattern":"File3DToSplat: not a PLY \\(missing end_header\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_extras/nodes_gaussian_splat.py","lineNumber":214,"sourceCode":"               'float': 'f4', 'double': 'f8', 'int8': 'i1', 'uint8': 'u1', 'int16': 'i2', 'uint16': 'u2',\n               'int32': 'i4', 'uint32': 'u4', 'float32': 'f4', 'float64': 'f8'}\n_KSPLAT_COMPRESSION = {  # level -> (bytesPerCenter, scale, rotation, color, shComponent, defaultScaleRange)\n    0: (12, 12, 16, 4, 4, 1), 1: (6, 6, 8, 4, 2, 32767), 2: (6, 6, 8, 4, 1, 32767)}\n_KSPLAT_SH_COMPONENTS = {0: 0, 1: 9, 2: 24, 3: 45}\n\n\ndef _rgb_to_sh_dc(rgb):\n    return ((np.asarray(rgb, np.float32) - 0.5) / _C0)[:, None, :]   # (N,3) base color -> (N,1,3) SH DC\n\n\ndef _norm_quat(q):\n    return q / np.linalg.norm(q, axis=1, keepdims=True).clip(1e-12)\n\n\ndef _parse_ply_gaussian(data: bytes):\n    end = data.find(b'end_header')\n    if end < 0:\n        raise ValueError(\"File3DToSplat: not a PLY (missing end_header)\")\n    header = data[:end].decode('ascii', 'replace')\n    body = end + len(b'end_header')\n    body += 2 if data[body:body + 2] == b'\\r\\n' else 1\n    count, props, in_vertex = 0, [], False\n    for line in header.splitlines():\n        p = line.split()\n        if not p:\n            continue\n        if p[0] == 'format' and p[1] != 'binary_little_endian':\n            raise ValueError(f\"File3DToSplat: unsupported PLY format '{p[1]}' (need binary_little_endian)\")\n        if p[0] == 'element':\n            in_vertex = p[1] == 'vertex'\n            if in_vertex:\n                count = int(p[2])\n        elif p[0] == 'property' and in_vertex:\n            if p[1] == 'list':\n                raise ValueError(\"File3DToSplat: PLY vertex has list properties (unsupported)\")\n            props.append((p[2], '<' + _PLY_DTYPES[p[1]]))","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_extras/nodes_gaussian_splat.py#L196-L232","documentation":"Raised by _parse_ply_gaussian when the input bytes selected as PLY (magic b'ply') contain no b'end_header' token anywhere. The parser splits the file at end_header to separate the ASCII header from the binary body; without it the file is not a complete PLY. This usually means the file is truncated, corrupted, or not actually a PLY despite its magic bytes.","triggerScenarios":"File3DToSplat loads a file whose first three bytes are 'ply' (so _detect_splat_format routes it to the PLY parser) but the header is cut off before end_header: truncated download, file saved mid-write, a text/HTML error page that happens to start with 'ply', or a header-only file.","commonSituations":"Interrupted or partial download of a .ply; a .ply written by another process still being written when read; wrong file passed to the node (renamed extension).","solutions":["Re-download or regenerate the .ply and confirm it opens in a PLY viewer.","Verify the file starts with a full 'ply\\nformat binary_little_endian 1.0\\n...\\nend_header\\n' header (inspect with a hex/text editor).","Check the file size against the source; a few-hundred-byte file is a stub or error page.","Ensure no process is still writing the file when ComfyUI reads it."],"exampleFix":"null","handlingStrategy":"validation","validationCode":"data = open(path, 'rb').read()\nif data[:3] != b'ply' or b'end_header' not in data[:65536]:\n    raise ValueError(f\"{path} is not a complete binary PLY\")","typeGuard":"def is_complete_ply(data: bytes) -> bool:\n    return data[:3] == b'ply' and b'end_header' in data","tryCatchPattern":"try:\n    result = _parse_ply_gaussian(data)\nexcept ValueError as e:\n    if 'missing end_header' in str(e):\n        re_download_or_regenerate(path)\n    else:\n        raise","preventionTips":["Verify downloads completed (size/mtime) before loading.","Sniff for both the 'ply' magic and an end_header line before parsing.","Never read a file another process is still writing."],"tags":["gaussian-splatting","ply","file-format","corrupt-file"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}