can1357/oh-my-pi · error · ArchiveError
Invalid ARJ extended header CRC32
Error message
Invalid ARJ extended header CRC32
What it means
Like basic headers, each ARJ extended header carries a CRC-32 over its payload, stored after the payload. parseArjBlock computes crc32 over the extension bytes and compares against the trailing u32; a mismatch means that extension's bytes are corrupted, so parsing stops rather than consuming untrusted extended metadata.
Source
Thrown at packages/utils/src/ar/arj.ts:86
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;
}
read(count: number): number {
if (!Number.isInteger(count) || count < 0 || count > 24 || this.#position + count > this.#bytes.byteLength * 8) {
throw new ArchiveError("Invalid ARJ method-4 compressed data: truncated bitstream");View on GitHub (pinned to 9690622007)
Solutions
- Test externally (`arj t` / 7-Zip) to confirm damage; restore the archive from backup or re-download.
- Identify which tool created/modified the file; re-create the archive with the original tool and default options.
- Re-pack the archive: extract what an external tolerant tool can, then rebuild it so all CRCs are recomputed.
- If writing ARJ files yourself, CRC-32 every extended-header payload and append it little-endian after the payload.
Defensive patterns
Strategy: try-catch
Try / catch
try {
return readArj(data, options);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("extended header CRC32")) {
// extended metadata is damaged; re-obtain or re-pack the archive
throw new Error(`ARJ extended header corrupt in ${sourceName}`);
}
throw err;
} Prevention
- Re-pack archives modified by third-party tools so all CRCs are regenerated.
- Verify binary-safe transfer with checksums before parsing.
- Run `arj t` / 7-Zip tests as a pre-parse gate on untrusted files.
When it happens
Trigger: During the extended-header walk in parseArjBlock: crc32(bytes[cursor..cursor+extensionSize]) differs from the u32 at cursor+extensionSize. Caused by byte corruption inside an extended header or a wrong extensionSize making the reader hash/verify the wrong region.
Common situations: Damaged downloads/media, archives modified by tools that rewrite extended headers (comments, timestamps, GOST/MD5 data) without recomputing their CRCs, or a corrupted chain where an earlier wrong size desynchronizes the CRC check of the next extension.
Related errors
- Invalid ARJ basic header CRC32
- Invalid ARJ archive: truncated ${what}
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ basic header size
- Invalid ARJ archive: too many extended headers
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1f232e6854a7da08.
Report an issue: GitHub.