{"record":{"id":"84b0970651e7b782","repo":"BabylonJS/Babylon.js","slug":"wrong-hufuncompress","errorCode":null,"errorMessage":"Wrong hufUncompress","messagePattern":"Wrong hufUncompress","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts","lineNumber":453,"sourceCode":"    const nBits = ParseUint32(dataView, offset);\r\n\r\n    offset.value += 4;\r\n\r\n    if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) {\r\n        throw new Error(\"Wrong HUF_ENCSIZE\");\r\n    }\r\n\r\n    const freq = new Array(HUF_ENCSIZE);\r\n    const hdec = new Array(HUF_DECSIZE);\r\n\r\n    HufClearDecTable(hdec);\r\n\r\n    const ni = nCompressed - (offset.value - initialInOffset);\r\n\r\n    HufUnpackEncTable(array, offset, ni, im, iM, freq);\r\n\r\n    if (nBits > 8 * (nCompressed - (offset.value - initialInOffset))) {\r\n        throw new Error(\"Wrong hufUncompress\");\r\n    }\r\n\r\n    HufBuildDecTable(freq, im, iM, hdec);\r\n\r\n    HufDecode(freq, hdec, array, offset, nBits, iM, nRaw, outBuffer, outOffset);\r\n}\r\n\r\nfunction UInt16(value: number) {\r\n    return value & 0xffff;\r\n}\r\n\r\nfunction Int16(value: number) {\r\n    const ref = UInt16(value);\r\n    return ref > 0x7fff ? ref - 0x10000 : ref;\r\n}\r\n\r\nfunction Wdec14(l: number, h: number) {\r\n    const ls = Int16(l);\r","sourceCodeStart":435,"sourceCodeEnd":471,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts#L435-L471","documentation":"After unpacking the Huffman encoding table, HufUncompress checks that the declared bit count (nBits) does not exceed the remaining compressed bytes (×8). If it does, the stream claims more payload bits than physically exist, so the data is incomplete/invalid and decoding is refused before HufDecode runs.","triggerScenarios":"Raised in HufUncompress (called by UncompressPIZ) when nCompressed was too small — typically the scanline block size/offset used to slice the huf data was wrong or the block was truncated.","commonSituations":"Truncated HTTP responses, incorrectly computed nCompressed when manually reading EXR chunk data, or a corrupt offset table pointing mid-block.","solutions":["Re-download the .exr and confirm it is not truncated","Verify the chunk's data size and offset come from the file's scanline offset table, not a hard-coded value","Confirm the file decompresses in a reference EXR tool","Re-export with a non-PIZ compression to rule out a writer bug"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (expectedByteLength && file.byteLength !== expectedByteLength) throw new Error(\"EXR truncated: got \" + file.byteLength + \" expected \" + expectedByteLength);","typeGuard":null,"tryCatchPattern":"try {\n  await loader.loadAsync(blob);\n} catch (e) {\n  if (/Wrong hufUncompress/.test(String(e))) {\n    // nBits exceeds remaining bytes → truncated block; re-fetch or use fallback asset\n    return loadFallbackTexture(url);\n  }\n  throw e;\n}","preventionTips":["Enforce Content-Length checks on downloads","Do not slice EXR ArrayBuffers manually; pass the whole file","Validate the scanline offset table when doing custom EXR chunk parsing","Re-export with non-PIZ compression for flaky pipelines"],"tags":["exr","piz-compression","truncated-data"],"backgroundTag":"corrupt-compressed-exr-data","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}