{"record":{"id":"29a1f2b554b590f0","repo":"can1357/oh-my-pi","slug":"invalid-lzh-common-extended-header","errorCode":null,"errorMessage":"Invalid LZH common extended header","messagePattern":"Invalid LZH common extended header","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":354,"sourceCode":"\tunicodeFilename?: string;\n\tunicodeDirectory?: string;\n\tmtimeMs?: number;\n\tmode?: number;\n\tpackedSize?: number;\n\tsize?: number;\n\tcommonCrc?: number;\n\tcommonCrcOffset?: number;\n}\n\nfunction processExtendedHeader(\n\ttype: number,\n\tdata: Uint8Array,\n\tabsoluteDataOffset: number,\n\tfields: LzhExtendedFields,\n): void {\n\tswitch (type) {\n\t\tcase 0x00:\n\t\t\tif (data.byteLength < 2) throw new ArchiveError(\"Invalid LZH common extended header\");\n\t\t\tfields.commonCrc = u16(data, 0);\n\t\t\tfields.commonCrcOffset = absoluteDataOffset;\n\t\t\tbreak;\n\t\tcase 0x01:\n\t\t\tfields.filename = decodeLegacy(data);\n\t\t\tbreak;\n\t\tcase 0x02:\n\t\t\tfields.directory = decodeLegacy(data).replaceAll(\"ÿ\", \"/\");\n\t\t\tbreak;\n\t\tcase 0x39:\n\t\t\tthrow new ArchiveError(\"Multi-volume LZH archives are unsupported\");\n\t\tcase 0x41:\n\t\t\tif (data.byteLength >= 16) {\n\t\t\t\tconst low = u32(data, 8);\n\t\t\t\tconst high = u32(data, 12);\n\t\t\t\tconst filetime = low + high * 0x100000000;\n\t\t\t\tif (Number.isSafeInteger(filetime)) fields.mtimeMs = filetime / 10_000 - 11_644_473_600_000;\n\t\t\t}","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L336-L372","documentation":"LZH extended header type 0x00 carries a CRC-16 over the common header area and must be at least 2 bytes (one u16). When the parsed data section is shorter than 2 bytes the header is malformed, so processExtendedHeader throws.","triggerScenarios":"Reading a level-1 or level-2 LZH member whose extended-header chain contains a type 0x00 entry with a data payload shorter than 2 bytes — caused by a wrong extension-size field, truncation, or a corrupt chain.","commonSituations":"Truncated downloads of .lzh files; archives edited by scripts that rewrote extended headers without fixing sizes; damaged floppy-era archives being recovered.","solutions":["Re-obtain the archive — a sub-2-byte 0x00 header means the size fields are corrupt","Check the file size against the expected checksum; if truncated, re-transfer","If you write LZH archives, ensure each extended header's size field covers type byte + data + 2-byte size trailer so parsing yields >= 2 data bytes for type 0x00","Catch ArchiveError around archive reads and surface a per-file corruption message instead of failing the whole batch"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"null","tryCatchPattern":"try {\n\tconst entries = await readArchive(lzhBytes);\n} catch (err) {\n\tif (err instanceof ArchiveError && err.message.includes(\"common extended header\")) {\n\t\t// header chain corrupt; surface per-file corruption instead of crashing\n\t\treturn { status: \"corrupt\", reason: \"lzh-common-header\" };\n\t}\n\tthrow err;\n}","preventionTips":["Re-download rather than repairing header bytes manually","Validate archives with an external extractor before batch processing","Check file sizes against expected values after transfer"],"tags":["archive","lzh","corrupt-header","checksum"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}