{"record":{"id":"7a2a13286c75045a","repo":"BabylonJS/Babylon.js","slug":"unexpected-end-of-file-after-hierarchy","errorCode":null,"errorMessage":"Unexpected end of file after HIERARCHY","messagePattern":"Unexpected end of file after HIERARCHY","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/loaders/src/BVH/bvhLoader.ts","lineNumber":346,"sourceCode":"    const { loopMode } = loadingOptions;\n\n    scene._blockEntityCollection = !!assetContainer;\n    const skeleton = new Skeleton(\"\", \"\", scene);\n    skeleton._parentContainer = assetContainer;\n    scene._blockEntityCollection = false;\n\n    const context = new LoaderContext(skeleton);\n    context.loopMode = loopMode;\n\n    // read model structure\n    const firstLine = lines.shift();\n    if (!firstLine || firstLine.trim().toUpperCase() !== _HierarchyNode) {\n        throw new Error(\"HIERARCHY expected\");\n    }\n\n    const nodeLine = lines.shift();\n    if (!nodeLine) {\n        throw new Error(\"Unexpected end of file after HIERARCHY\");\n    }\n    const root = ReadNode(lines, nodeLine.trim(), null, context);\n\n    // read motion data\n    const motionLine = lines.shift();\n    if (!motionLine || motionLine.trim().toUpperCase() !== _MotionNode) {\n        throw new Error(\"MOTION expected\");\n    }\n\n    const framesLine = lines.shift();\n    if (!framesLine) {\n        throw new Error(\"Unexpected end of file before frame count\");\n    }\n    const framesTokens = framesLine.trim().split(/[\\s]+/);\n    if (framesTokens.length < 2) {\n        throw new Error(\"Invalid frame count line\");\n    }\n","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/loaders/src/BVH/bvhLoader.ts#L328-L364","documentation":"ReadBvh parses a BVH motion-capture file line by line and requires the file to begin with a 'HIERARCHY' keyword followed immediately by the root node line (e.g. 'ROOT Hips'). This error is thrown when lines.shift() returns undefined after the HIERARCHY keyword was consumed, meaning the text ended before any root node line was found. The library throws it because the hierarchy section cannot exist without at least one root joint, so parsing must abort.","triggerScenarios":"Calling ReadBvh (directly or via the BVH loader) with text that contains only 'HIERARCHY' as its first line and nothing else, e.g. an empty/placeholder BVH string, a file whose content after 'HIERARCHY' was stripped, or text passed without a trailing root line due to faulty preprocessing that split/filtered lines.","commonSituations":"Downloading a truncated .bvh file (network cut mid-transfer), opening a zero-byte or header-only file, passing an empty string or a CORS/404 HTML error body that coincidentally only reaches the first token, or a build step that inlined only part of the asset.","solutions":["Check the BVH source file/text is complete: it must contain 'HIERARCHY' followed by a 'ROOT <name>' line; re-download or re-export the file.","Verify you are not passing an empty string or an error-page body to ReadBvh; log text.length and the first 3 lines before calling.","Ensure any line-splitting/preprocessing keeps the root line (don't slice the lines array before passing text).","Confirm the file uses '\\n' (or '\\r\\n') line endings; a lone 'HIERARCHY' with no newline plus binary garbage can still surface as truncation — validate the raw bytes.","Wrap the load call in try/catch and fall back to a known-good default BVH asset."],"exampleFix":"// before\nconst text = await fetch(url).then((r) => r.text());\nconst skeleton = ReadBvh(text, scene, null, options);\n\n// after\nconst res = await fetch(url);\nif (!res.ok) throw new Error(`Failed to load BVH: ${res.status}`);\nconst text = await res.text();\nif (!/HIERARCHY\\s+ROOT\\s+\\S+/i.test(text)) {\n    throw new Error(`Truncated BVH asset at ${url}`);\n}\nconst skeleton = ReadBvh(text, scene, null, options);","handlingStrategy":"validation","validationCode":"function isValidBvhHeader(text: string): boolean {\n    const lines = text.split(/\\r?\\n/).map((l) => l.trim());\n    return lines.length >= 2 && lines[0].toUpperCase() === \"HIERARCHY\" && /^ROOT\\s+\\S+/i.test(lines[1]);\n}\nif (!isValidBvhHeader(bvhText)) throw new Error(\"BVH asset truncated before root node\");\nconst skeleton = ReadBvh(bvhText, scene, null, options);","typeGuard":null,"tryCatchPattern":"let skeleton: Skeleton;\ntry {\n    skeleton = ReadBvh(bvhText, scene, null, options);\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"end of file\")) {\n        console.error(\"BVH file is truncated/incomplete\", e);\n        skeleton = loadFallbackSkeleton(scene);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Check HTTP status and content-length when loading .bvh assets and compare against expected file size.","Log the first/last lines of the BVH text before parsing to catch truncation early.","Keep BVH assets in version control or with checksums so corruption is detectable.","Never pass fetch error-page bodies straight to ReadBvh; gate on res.ok."],"tags":["bvh","parser","mocap","truncated-file"],"backgroundTag":"bvh-malformed-file","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}