{"record":{"id":"6572b0ad5a79f0b0","repo":"can1357/oh-my-pi","slug":"invalid-lzh-unix-permissions-extended-header","errorCode":null,"errorMessage":"Invalid LZH Unix permissions extended header","messagePattern":"Invalid LZH Unix permissions extended header","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":386,"sourceCode":"\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}\n\t\t\tbreak;\n\t\tcase 0x42:\n\t\t\tif (data.byteLength < 16) throw new ArchiveError(\"Invalid LZH 64-bit size extended header\");\n\t\t\tfields.packedSize = u64(data, 0);\n\t\t\tfields.size = u64(data, 8);\n\t\t\tbreak;\n\t\tcase 0x44:\n\t\t\tfields.unicodeFilename = decodeUtf16(data);\n\t\t\tbreak;\n\t\tcase 0x45:\n\t\t\tfields.unicodeDirectory = decodeUtf16(data).replaceAll(\"ÿ\", \"/\");\n\t\t\tbreak;\n\t\tcase 0x50:\n\t\t\tif (data.byteLength < 2) throw new ArchiveError(\"Invalid LZH Unix permissions extended header\");\n\t\t\tfields.mode = u16(data, 0);\n\t\t\tbreak;\n\t\tcase 0x54:\n\t\t\tif (data.byteLength < 4) throw new ArchiveError(\"Invalid LZH Unix timestamp extended header\");\n\t\t\tfields.mtimeMs = u32(data, 0) * 1000;\n\t\t\tbreak;\n\t}\n}\n\nclass LzhMemberSource implements MemberSource {\n\treadonly #archive: Uint8Array;\n\treadonly #start: number;\n\treadonly #packedSize: number;\n\treadonly #method: string;\n\treadonly #crc: number;\n\n\tconstructor(archive: Uint8Array, start: number, packedSize: number, method: string, crc: number) {\n\t\tthis.#archive = archive;","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L368-L404","documentation":"Extended header type 0x50 stores Unix permission bits as a u16 and must be at least 2 bytes long. A shorter payload means the header chain is malformed, so the reader throws rather than guessing a mode.","triggerScenarios":"Reading an LZH level-1/2 member whose extended-header chain contains a type 0x50 entry with fewer than 2 data bytes — corrupt size field, truncation, or a buggy writer.","commonSituations":"Unix-created .lzh archives (LHA for Linux, lhasa) with damaged headers; archives whose extended headers were rewritten by scripts; partially recovered files.","solutions":["Re-obtain the archive — the header size chain is corrupt","Verify with an external tool (7-Zip, lha) which member's headers are damaged and repair/skip it","If you write LZH archives, ensure type 0x50 headers carry exactly 2 bytes (u16 LE mode) plus the size trailer","Treat missing permission info gracefully in your app by catching ArchiveError and defaulting modes"],"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(\"Unix permissions extended header\")) {\n\t\t// fall back to default modes or re-acquire the archive\n\t}\n\tthrow err;\n}","preventionTips":["Validate Unix-created .lzh files with lhasa/7-Zip before automated ingestion","Do not rewrite extended headers with ad-hoc scripts","Store and check transfer checksums"],"tags":["archive","lzh","corrupt-header","permissions"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}