{"record":{"id":"2d8a2bd0265c3b79","repo":"can1357/oh-my-pi","slug":"invalid-lzh-level-level-header-size","errorCode":null,"errorMessage":"Invalid LZH level-${level} header size","messagePattern":"Invalid LZH level-(.+?) header size","errorType":"validation","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":479,"sourceCode":"function parseLzhHeader(bytes: Uint8Array, offset: number, options: FormatReadOptions): ParsedLzhHeader {\n\tassertRange(bytes, offset, offset + 22, \"header\");\n\tconst level = bytes[offset + 20]!;\n\tif (level > 2) throw new ArchiveError(`Unsupported LZH header level ${level}`);\n\tconst method = String.fromCharCode(...bytes.subarray(offset + 2, offset + 7));\n\tif (!LHA_METHOD_PATTERN.test(method)) throw new ArchiveError(`Invalid LZH compression method '${method}'`);\n\tlet packedSize = u32(bytes, offset + 7);\n\tlet size = u32(bytes, offset + 11);\n\tlet crc = 0;\n\tlet legacyFilename: string | undefined;\n\tlet mtimeMs: number | undefined;\n\tlet osId = 0;\n\tlet dataStart: number;\n\tconst fields: LzhExtendedFields = {};\n\n\tif (level < 2) {\n\t\tconst headerLength = bytes[offset]!;\n\t\tconst minimum = level === 0 ? 22 : 25;\n\t\tif (headerLength < minimum) throw new ArchiveError(`Invalid LZH level-${level} header size`);\n\t\tconst baseEnd = offset + headerLength + 2;\n\t\tassertRange(bytes, offset, baseEnd, \"header\");\n\t\tlet sum = 0;\n\t\tfor (let index = offset + 2; index < baseEnd; index++) sum = (sum + bytes[index]!) & 0xff;\n\t\tif (sum !== bytes[offset + 1]) throw new ArchiveError(\"Invalid LZH header checksum\");\n\t\tconst nameLength = bytes[offset + 21]!;\n\t\tif (22 + nameLength + 2 > headerLength + 2) throw new ArchiveError(\"Invalid LZH filename length\");\n\t\tassertArchivePathBytes(nameLength, \"member path\", options.limits.maxPathBytes);\n\t\tlegacyFilename = decodeLegacy(bytes.subarray(offset + 22, offset + 22 + nameLength));\n\t\tcrc = u16(bytes, offset + 22 + nameLength);\n\t\tmtimeMs = dosTimeToMs(u32(bytes, offset + 15));\n\t\tif (level === 0) {\n\t\t\tconst extendedStart = offset + 24 + nameLength;\n\t\t\tif (baseEnd - extendedStart >= 12) {\n\t\t\t\tconst extended = bytes.subarray(extendedStart, baseEnd);\n\t\t\t\tif ((extended[0] === 0x55 || extended[0] === 0x4b) && extended[1] === 0) {\n\t\t\t\t\tosId = extended[0]!;\n\t\t\t\t\tfields.mtimeMs = u32(extended, 2) * 1000;","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L461-L497","documentation":"Thrown when a level-0 or level-1 LZH header's declared length byte is smaller than the minimum structurally required size (22 bytes for level 0, 25 for level 1). The header cannot possibly contain the mandatory fields, so parsing aborts.","triggerScenarios":"Reading an archive with a truncated or corrupt header-length byte, or a forged/minimized header written by a broken tool.","commonSituations":"Partially downloaded .lzh files, archives damaged in storage, or fuzzed/malicious inputs.","solutions":["Replace the archive with an intact copy and verify its size/checksum","Repack the source files into a fresh LHA archive","If processing untrusted input, catch ArchiveError and reject the file"],"exampleFix":"// before: trusting any byte blob as a member\nfor (const member of lzhMembers(bytes)) { ... }\n// after: guard the read\ntry {\n  for (const member of lzhMembers(bytes)) { ... }\n} catch (err) {\n  if (err instanceof ArchiveError) throw new Error(`corrupt LZH: ${err.message}`);\n  throw err;\n}","handlingStrategy":"validation","validationCode":"if (bytes.byteLength < 24) throw new Error('too small to be an LZH member');","typeGuard":null,"tryCatchPattern":"try { parse(); } catch (err) { if (err instanceof ArchiveError && /header size/.test(err.message)) skip(err); else throw err; }","preventionTips":["Validate minimum sizes before parse","Track archive provenance"],"tags":["archive","lzh","header","corruption"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}