{"record":{"id":"db9d01d25dfec721","repo":"BabylonJS/Babylon.js","slug":"error-in-hufunpackenctable","errorCode":null,"errorMessage":"Error in HufUnpackEncTable","messagePattern":"Error in HufUnpackEncTable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts","lineNumber":232,"sourceCode":"    let c = 0;\r\n    let lc = 0;\r\n\r\n    for (; im <= iM; im++) {\r\n        if (p.value - offset.value > ni) {\r\n            return;\r\n        }\r\n\r\n        let gb = GetBits(6, c, lc, array, p);\r\n\r\n        const l = gb.l;\r\n        c = gb.c;\r\n        lc = gb.lc;\r\n\r\n        hcode[im] = l;\r\n\r\n        if (l == LONG_ZEROCODE_RUN) {\r\n            if (p.value - offset.value > ni) {\r\n                throw new Error(\"Error in HufUnpackEncTable\");\r\n            }\r\n\r\n            gb = GetBits(8, c, lc, array, p);\r\n\r\n            let zerun = gb.l + SHORTEST_LONG_RUN;\r\n            c = gb.c;\r\n            lc = gb.lc;\r\n\r\n            if (im + zerun > iM + 1) {\r\n                throw new Error(\"Error in HufUnpackEncTable\");\r\n            }\r\n\r\n            while (zerun--) {\r\n                hcode[im++] = 0;\r\n            }\r\n\r\n            im--;\r\n        } else if (l >= SHORT_ZEROCODE_RUN) {\r","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts#L214-L250","documentation":"HufUnpackEncTable decodes the Huffman encoder table from an EXR file's compressed pixel data. When it encounters a LONG_ZEROCODE_RUN, the run-length count must fit within the remaining code entries (ni). If the decoded run would exceed the table, the data is corrupt or malformed, so the loader throws this error rather than producing a broken Huffman table.","triggerScenarios":"Loading a corrupt/truncated EXR file (compression type with huf compression, e.g., PIZ/PIZ_COMPRESSION or DWA) whose huf compressed table contains a long zero-code run longer than the number of remaining entries.","commonSituations":"EXR downloaded incompletely (truncated HTTP body); EXR produced by a buggy encoder; corrupted file from transfer/storage; wrong bytes served (HTML error page or wrong content-type) parsed as EXR.","solutions":["Re-obtain/verify the EXR file: check integrity (file size, checksum) and re-download; confirm it opens in a tool like OpenEXR's exrheader/exrdisplay","Confirm the EXR uses a supported compression and is a valid OpenEXR v2 file; re-export/convert it (e.g., with `oiiotool in.exr -o out.exr`)","Verify the server serves the complete binary with correct Content-Type (image/avax) and no encoding/transformation mangling the bytes","If the file is known-good, report to Babylon.js with the failing EXR; meanwhile load a losslessly re-encoded (e.g., ZIP-compressed) version"],"exampleFix":"// before\nconst cube = CubeTexture.Load('scene/env.hdr.exr'); // corrupt file -> throws in HufUnpackEncTable\n// after\nfetch('scene/env.exr')\n  .then((r) => { if (!r.ok || !Number(r.headers.get('content-length'))) throw new Error('incomplete EXR'); return r.blob(); })\n  .then((b) => { /* verify integrity, then load */ });","handlingStrategy":"validation","validationCode":"async function loadVerifiedExr(url: string, scene: BABYLON.Scene): Promise<BABYLON.BaseTexture> {\n    const res = await fetch(url);\n    if (!res.ok) throw new Error(`EXR fetch failed: ${res.status}`);\n    const buf = await res.arrayBuffer();\n    const magic = new Uint8Array(buf, 0, 4);\n    const isExr = magic[0] === 0x76 && magic[1] === 0x2f && magic[2] === 0x31 && magic[3] === 0x01;\n    if (!isExr || buf.byteLength === 0) throw new Error('Corrupt or non-EXR payload');\n    return new BABYLON.CubeTexture(url, scene);\n}","typeGuard":"function isOpenExrBuffer(buf: ArrayBuffer): boolean {\n    if (buf.byteLength < 4) return false;\n    const m = new Uint8Array(buf, 0, 4);\n    return m[0] === 0x76 && m[1] === 0x2f && m[2] === 0x31 && m[3] === 0x01;\n}","tryCatchPattern":"try {\n    const texture = new BABYLON.CubeTexture('env.exr', scene);\n    return texture;\n} catch (e) {\n    if (String(e?.message).includes('HufUnpackEncTable')) {\n        console.error('EXR huf data corrupt; re-download or re-encode the asset', e);\n        return null; // or load .env fallback\n    }\n    throw e;\n}","preventionTips":["Serve EXR with correct Content-Length and binary-safe transfer (no text-mode/gzip mangling)","Checksum-verify large EXR assets after download","Re-encode source EXRs with standard tools (oiiotool/OpenEXR) before shipping","Validate the EXR magic bytes (0x76 0x2f 0x31 0x01) before handing the file to the loader"],"tags":["exr","huffman","corrupt-file","texture-loading","piz-compression"],"backgroundTag":"corrupt-compressed-asset","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}