can1357/oh-my-pi · error · ArchiveError
Invalid ARJ archive: too many extended headers
Error message
Invalid ARJ archive: too many extended headers
What it means
ARJ headers may be followed by a chain of extended headers, each a 16-bit size (0 terminates the chain). This reader caps the chain at 65,535 entries; exceeding that means the loop is not finding its terminator and would run unboundedly over the buffer, so it throws to bound work on malformed input.
Source
Thrown at packages/utils/src/ar/arj.ts:83
}
const bodySize = u16(bytes, offset + 2);
if (bodySize === 0)
return { bodyStart: offset + 4, bodySize: 0, nextOffset: offset + 4, metadataSize: 4, isEnd: true };
if (bodySize < 30 || bodySize > ARJ_MAX_BASIC_HEADER) throw new ArchiveError("Invalid ARJ basic header size");
const bodyStart = offset + 4;
const bodyEnd = bodyStart + bodySize;
assertRange(bytes, bodyStart, bodyEnd + 4, "basic header");
if (crc32(bytes.subarray(bodyStart, bodyEnd)) !== u32(bytes, bodyEnd)) {
throw new ArchiveError("Invalid ARJ basic header CRC32");
}
let cursor = bodyEnd + 4;
let extensionCount = 0;
for (;;) {
assertRange(bytes, cursor, cursor + 2, "extended header size");
const extensionSize = u16(bytes, cursor);
cursor += 2;
if (extensionSize === 0) break;
if (++extensionCount > 65_535) throw new ArchiveError("Invalid ARJ archive: too many extended headers");
assertRange(bytes, cursor, cursor + extensionSize + 4, "extended header");
if (crc32(bytes.subarray(cursor, cursor + extensionSize)) !== u32(bytes, cursor + extensionSize)) {
throw new ArchiveError("Invalid ARJ extended header CRC32");
}
cursor += extensionSize + 4;
assertIndexSize(cursor - offset, options.limits, "header metadata");
}
return { bodyStart, bodySize, nextOffset: cursor, metadataSize: cursor - offset, isEnd: false };
}
class ArjBitReader {
readonly #bytes: Uint8Array;
#position = 0;
constructor(bytes: Uint8Array) {
this.#bytes = bytes;
}
View on GitHub (pinned to 9690622007)
Solutions
- Treat the file as malicious or severely corrupt: do not attempt repair; obtain the archive from a trusted source.
- Confirm with an external test (`arj t`) whether the archive is otherwise valid; if not, discard it.
- If you produce ARJ files, always terminate the extended-header chain with a 0x0000 size word before the next block.
- Keep the library's limits (options.limits) in place — do not raise them to 'make the file parse'; this error indicates malformed structure, not a too-small budget.
Defensive patterns
Strategy: try-catch
Try / catch
try {
return readArj(data, options);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("too many extended headers")) {
// treat as malformed/hostile input: reject outright
throw new Error("ARJ rejected: extended-header chain does not terminate");
}
throw err;
} Prevention
- Treat this error as a sign of a malicious or badly corrupt archive — never raise limits to work around it.
- Validate untrusted archives out-of-process or with timeouts so malformed input cannot stall pipelines.
- Ensure any ARJ writer you use terminates extended-header chains with a 0x0000 size.
When it happens
Trigger: parseArjBlock() walks 65,536+ non-zero extension sizes without hitting a 0 u16 — a corrupt or malicious archive whose extended-header chain never terminates, or garbage after the basic header interpreted as extension sizes.
Common situations: Fuzzed/attacker-crafted archives (this cap is a DoS guard), a corrupted file where the terminating 0x0000 was overwritten, or bytes after the basic header belonging to a different structure because the header size itself was wrong.
Related errors
- Invalid RPM package: ${what} header is too large
- Invalid ARJ archive: truncated ${what}
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ basic header size
- Invalid ARJ basic header CRC32
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8dbe4cf49464918e.
Report an issue: GitHub.