can1357/oh-my-pi · error · ArchiveError
Invalid LZH extended header size
Error message
Invalid LZH extended header size
What it means
Thrown while walking a level-1 LZH header's chain of extended headers when an extension records a size smaller than the 3-byte minimum (2-byte size field + 1 type byte). Such a record cannot exist in the format, so the header chain is corrupt.
Source
Thrown at packages/utils/src/ar/lzh.ts:509
if (level === 0) {
const extendedStart = offset + 24 + nameLength;
if (baseEnd - extendedStart >= 12) {
const extended = bytes.subarray(extendedStart, baseEnd);
if ((extended[0] === 0x55 || extended[0] === 0x4b) && extended[1] === 0) {
osId = extended[0]!;
fields.mtimeMs = u32(extended, 2) * 1000;
fields.mode = u16(extended, extended.byteLength - 6);
}
}
dataStart = baseEnd;
} else {
osId = bytes[offset + 24 + nameLength]!;
let extensionSize = u16(bytes, baseEnd - 2);
let cursor = baseEnd;
let totalExtensionSize = 0;
let extensionCount = 0;
while (extensionSize !== 0) {
if (extensionSize < 3) throw new ArchiveError("Invalid LZH extended header size");
assertRange(bytes, cursor, cursor + extensionSize, "extended header");
totalExtensionSize += extensionSize;
assertIndexSize(headerLength + 2 + totalExtensionSize, options.limits, "header metadata");
if (++extensionCount > 65_535) throw new ArchiveError("Invalid LZH archive: too many extended headers");
const type = bytes[cursor]!;
const dataEnd = cursor + extensionSize - 2;
const data = bytes.subarray(cursor + 1, dataEnd);
if (type === 0x01 || type === 0x02 || type === 0x44 || type === 0x45) {
assertArchivePathBytes(data.byteLength, "member path", options.limits.maxPathBytes);
}
processExtendedHeader(type, data, cursor + 1, fields);
const currentSize = extensionSize;
extensionSize = u16(bytes, dataEnd);
cursor += currentSize;
}
dataStart = baseEnd + totalExtensionSize;
packedSize = fields.packedSize ?? packedSize - totalExtensionSize;
if (packedSize < 0) throw new ArchiveError("Invalid LZH level-1 packed size");View on GitHub (pinned to 9690622007)
Solutions
- Obtain an intact copy of the archive
- Repack with a conforming LHA tool
- Reject the file if input is untrusted — the chain is unrecoverable without heuristics
Example fix
null
Defensive patterns
Strategy: try-catch
Try / catch
try { parse(); } catch (err) { if (err instanceof ArchiveError && err.message.includes('extended header')) reject(err); else throw err; } Prevention
- Avoid level-1 archives when possible
- Fuzz-test your ingestion path
When it happens
Trigger: Parsing an archive whose extended-header chain contains a zero-corrupted or miscomputed size field, or where a prior extension's size was wrong so the cursor lands mid-field.
Common situations: Damaged archives, non-conforming writers, or fuzzed inputs exercising the extension-chain loop.
Related errors
- Invalid LZH filename length
- Invalid LZH archive: too many extended headers
- Invalid LZH level-1 packed size
- Invalid CAB archive: folder data is shorter than its file ta
- Invalid CAB archive: uncompressed CFDATA sizes do not match
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3b8caee1cc4ec124.
Report an issue: GitHub.