{"record":{"id":"9f589e0593561e3c","repo":"can1357/oh-my-pi","slug":"invalid-label-command-huffman-table","errorCode":null,"errorMessage":"Invalid ${label} command Huffman table","messagePattern":"Invalid (.+?) command Huffman table","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":172,"sourceCode":"\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`);\n\t\t\tindex += skipped;\n\t\t} else {\n\t\t\tlengths[index++] = code - 2;\n\t\t}\n\t}\n\treturn CanonicalHuffman.build(lengths, symbolCount, label);\n}\n\nfunction readPositionTree(\n\treader: MsbBitReader,\n\tpositionBits: number,\n\tsymbolCount: number,\n\tlabel: string,\n): CanonicalHuffman {\n\tconst encodedCount = reader.read(positionBits);\n\tif (encodedCount === 0) return CanonicalHuffman.single(reader.read(positionBits), symbolCount, label);\n\tif (encodedCount > symbolCount) throw new ArchiveError(`Invalid ${label} position Huffman table size`);\n\tconst lengths = new Uint8Array(symbolCount);","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L154-L190","documentation":"readCommandTree decodes the per-block command Huffman code-length table. When a run-length skip entry (code 0/1/2) would skip past the declared number of encoded symbols, the table is corrupt or misaligned, so the library refuses to build it.","triggerScenarios":"Calling decompressLhStatic (via the LZH/ARJ read APIs) on a stream whose 16-bit block header or code-length table bits are corrupt, truncated-and-resumed, or whose bit reader is misaligned because an earlier field was parsed at the wrong offset.","commonSituations":"Corrupted archives from failed downloads or bad media; hand-crafted/fuzzed archives; using the wrong method label/dictionary size for a variant (e.g. ARJ method 1-3 vs -lh5-..-lh7-), which shifts bit boundaries.","solutions":["Re-obtain or re-extract the archive; verify checksum/CRC of the source file","Confirm the correct method/positionBits/positionSymbols parameters for the archive variant being decoded","Check that decompression starts exactly at the compressed-data offset (extended headers consumed correctly)","If the input is untrusted, expect and handle ArchiveError rather than treating it as a bug"],"exampleFix":"// before\ntry { out = decompressLhStatic(packed, outSize, 5, 256, \"LZH -lh5-\"); }\ncatch (e) { /* crash */ }\n// after\ntry {\n  out = decompressLhStatic(packed, outSize, 5, 256, \"LZH -lh5-\");\n} catch (e) {\n  if (e instanceof ArchiveError) {\n    console.error(\"Archive corrupt or unsupported variant:\", e.message);\n    out = null;\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Can't pre-validate Huffman tables without decoding; at minimum sanity-check input\nif (packed.length === 0 || outSize <= 0) throw new Error(\"bad decompress inputs\");","typeGuard":null,"tryCatchPattern":"try {\n  const out = decompressLhStatic(packed, outSize, positionBits, positionSymbols, label);\n} catch (err) {\n  if (err instanceof ArchiveError) return null; // treat member as corrupt\n  throw err;\n}","preventionTips":["Verify archive integrity (CRC) before extraction","Pass method-correct positionBits/positionSymbols parameters","Start decoding at the true data offset after extended headers"],"tags":["archive","corruption","huffman","lzh"],"backgroundTag":"corrupt-archive-data","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}