{"record":{"id":"99f335cc8b689dd4","repo":"BabylonJS/Babylon.js","slug":"invalid-table-entry","errorCode":null,"errorMessage":"Invalid table entry","messagePattern":"Invalid table entry","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts","lineNumber":282,"sourceCode":"\r\n    HufCanonicalCodeTable(hcode);\r\n}\r\n\r\nfunction HufLength(code: number) {\r\n    return code & 63;\r\n}\r\n\r\nfunction HufCode(code: number) {\r\n    return code >> 6;\r\n}\r\n\r\nfunction HufBuildDecTable(hcode: Array<any>, im: number, iM: number, hdecod: Array<any>) {\r\n    for (; im <= iM; im++) {\r\n        const c = HufCode(hcode[im]);\r\n        const l = HufLength(hcode[im]);\r\n\r\n        if (c >> l) {\r\n            throw new Error(\"Invalid table entry\");\r\n        }\r\n\r\n        if (l > HUF_DECBITS) {\r\n            const pl = hdecod[c >> (l - HUF_DECBITS)];\r\n\r\n            if (pl.len) {\r\n                throw new Error(\"Invalid table entry\");\r\n            }\r\n\r\n            pl.lit++;\r\n\r\n            if (pl.p) {\r\n                const p = pl.p;\r\n                pl.p = new Array(pl.lit);\r\n\r\n                for (let i = 0; i < pl.lit - 1; ++i) {\r\n                    pl.p[i] = p[i];\r\n                }\r","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/Loaders/EXR/exrLoader.compression.huf.ts#L264-L300","documentation":"HufBuildDecTable builds the fast lookup table used by Babylon.js's EXR huf decoder. When decompressing a huf-compressed EXR block, if a canonical Huffman code's value does not fit within its bit length (`c >> l !== 0`) the code table is internally inconsistent, so the loader throws \"Invalid table entry\" instead of producing garbage pixels. It is thrown only while decoding huf-compressed EXR data via HufUncompress.","triggerScenarios":"Loading a huf-compressed EXR file whose huf code table decodes to a symbol whose code value exceeds its declared bit length — i.e. the compressed stream or its header (im..iM code entries) is corrupt, truncated, or was not produced by a valid huf encoder.","commonSituations":"Corrupted or partially downloaded .exr files; hand-edited or re-wrapped EXR files; files produced by buggy third-party EXR writers; serving EXR assets through a proxy/CDN that truncates or re-encodes binary data; loading a non-huf or damaged EXR with LoadTextures/EXRLoader.","solutions":["Re-obtain or re-export the .exr file from a trusted source/encoder (e.g. re-save with OpenEXR tooling) to rule out corruption.","Verify the file transfers intact: compare byte size/checksum of the served asset against the original; ensure the server sends correct Content-Length and no text/error pages are decoded as EXR.","Try loading the EXR without huf compression (export with zip/zip16/piz/rle compression) or convert to another supported format.","Wrap the load in error handling and surface the message so users know the asset, not the app, is at fault."],"exampleFix":"// before\nscene.loadTexture('render.exr', ...); // throws if file is corrupt\n// after\nengine.onTextureLoadError = (msg) => console.warn('EXR asset invalid, using fallback:', msg);\nscene.loadTexture('render.exr', onLoad, () => scene.loadTexture('render.png', onLoad));","handlingStrategy":"try-catch","validationCode":"async function isValidExr(url) {\n  const res = await fetch(url);\n  const buf = new Uint8Array(await res.arrayBuffer());\n  if (buf.length < 8) return false;\n  const magic = 20000630; // OpenEXR magic number\n  const view = new DataView(buf.buffer);\n  return view.getUint32(0, true) === magic && buf.length >= res.headers.get('content-length') * 1 || view.getUint32(0, true) === magic;\n}\n// call before loading: if (!(await isValidExr(url))) useFallbackTexture();","typeGuard":"function isExrBuffer(data) {\n  return data instanceof ArrayBuffer &&\n    data.byteLength >= 8 &&\n    new DataView(data).getUint32(0, true) === 20000630;\n}","tryCatchPattern":"try {\n  const texture = await scene.loadTextureAsync('render.exr');\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid table entry') {\n    console.error('EXR huf data is corrupt; re-export the asset without huf compression.');\n    useFallbackTexture();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Serve .exr files with integrity checks (ETag + checksum comparison after download).","Prefer zip/zip16 or piz compression when exporting EXRs for web consumption.","Never let generic middleware (HTML rewrites, double compression) touch binary texture routes.","Pre-validate the OpenEXR magic number (0x76, 0x2f, 0x31, 0x01) before handing bytes to the loader."],"tags":["exr","huf-decompression","corrupt-data","texture-loading"],"backgroundTag":"exr-huf-invalid-table-entry","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}