{"record":{"id":"8258d3c14ef853ea","repo":"can1357/oh-my-pi","slug":"invalid-label-temporary-huffman-table","errorCode":null,"errorMessage":"Invalid ${label} temporary Huffman table","messagePattern":"Invalid (.+?) temporary Huffman table","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":154,"sourceCode":"\t\t\tlength++;\n\t\t\tif (length > 16) throw new ArchiveError(`Invalid ${label} Huffman table: code is too long`);\n\t\t}\n\t}\n\treturn length;\n}\n\nfunction readTemporaryTree(reader: MsbBitReader, label: string): CanonicalHuffman {\n\tconst symbolCount = 19;\n\tconst encodedCount = reader.read(5);\n\tif (encodedCount === 0) return CanonicalHuffman.single(reader.read(5), symbolCount, label);\n\tif (encodedCount > symbolCount) throw new ArchiveError(`Invalid ${label} temporary Huffman table size`);\n\tconst lengths = new Uint8Array(symbolCount);\n\tlet index = 0;\n\twhile (index < encodedCount) {\n\t\tlengths[index++] = readCodeLength(reader, label);\n\t\tif (index === 3) {\n\t\t\tconst skipped = reader.read(2);\n\t\t\tif (index + skipped > encodedCount) throw new ArchiveError(`Invalid ${label} temporary Huffman table`);\n\t\t\tindex += skipped;\n\t\t}\n\t}\n\treturn CanonicalHuffman.build(lengths, symbolCount, label);\n}\n\nfunction readCommandTree(reader: MsbBitReader, temporary: CanonicalHuffman, label: string): CanonicalHuffman {\n\tconst symbolCount = 510;\n\tconst encodedCount = reader.read(9);\n\tif (encodedCount === 0) return CanonicalHuffman.single(reader.read(9), symbolCount, label);\n\tif (encodedCount > symbolCount) throw new ArchiveError(`Invalid ${label} command Huffman table size`);\n\tconst lengths = new Uint8Array(symbolCount);\n\tlet index = 0;\n\twhile (index < encodedCount) {\n\t\tconst code = temporary.decode(reader);\n\t\tif (code <= 2) {\n\t\t\tconst skipped = code === 0 ? 1 : code === 1 ? reader.read(4) + 3 : reader.read(9) + 20;\n\t\t\tif (index + skipped > encodedCount) throw new ArchiveError(`Invalid ${label} command Huffman table`);","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L136-L172","documentation":"While reading the temporary table's lengths, after every 3 lengths the format encodes a 2-bit skip count. If the skip would advance the index past the declared encodedCount, the stream is internally inconsistent (declares more symbols than it provides room for), so readTemporaryTree() throws ArchiveError instead of building an invalid table.","triggerScenarios":"Corrupted 2-bit skip fields in the temporary-table section (values pushing index beyond encodedCount), bit misalignment from an earlier misparse, or hand-crafted/fuzzed table bytes.","commonSituations":"Damaged archives, wrong-offset parsing, fuzz inputs targeting the skip-field logic.","solutions":["Validate the archive externally (unlha -t / CRC) and re-download if it fails","Confirm the reader position: any earlier table-field misparse shifts all subsequent bits","If generating archives, emit skip counts consistent with the declared encodedCount","Catch ArchiveError and treat the file as corrupt"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const out = decompressLhStatic(data, size);\n} catch (err) {\n  if (err instanceof ArchiveError) {\n    return { ok: false, reason: 'corrupt-temporary-table' };\n  }\n  throw err;\n}","preventionTips":["Check archive CRC before extraction","Fix any earlier misparse — skip-field errors usually stem from a shifted bit position","Ensure encoders emit skip counts consistent with encodedCount","Fail fast; corrupted tables never self-heal on retry"],"tags":["archive","huffman","lzh","corruption","validation"],"backgroundTag":"corrupt-huffman-table","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}