can1357/oh-my-pi · error · ArchiveError

Invalid ARJ main header

Error message

Invalid ARJ main header

What it means

This ArchiveError is thrown when the ARJ main header's first-header-size byte is out of range (< 30 or larger than the basic header body) or its archiver-version byte (offset 6) is not 2. The signature and header CRC passed, but the main header content is structurally invalid for this reader.

Solutions

  1. Verify the archive with the official arj tool to confirm whether it is standard-compliant.
  2. Recreate the archive with standard ARJ or a well-known compatible tool.
  3. Check the producing tool's version; security-enhanced ARJ variants may need their own reader.
  4. If corruption is suspected, re-download and compare checksums.

Example fix

// before
const entries = await readArj(source, options);
// after
try {
  const entries = await readArj(source, options);
} catch (e) {
  if (e instanceof ArchiveError && e.message === 'Invalid ARJ main header') {
    throw new Error('archive main header is malformed or from an unsupported ARJ variant; re-pack with standard ARJ');
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// main header body byte 6 must be the archiver version (2)
// and byte 0 the first-header size (>= 30) — verify after sniff
if (bytes[4] < 30 || bytes[4 + u16(bytes, 2)] === undefined || bytes[4 + 6] !== 2) {
  throw new Error('non-standard ARJ main header; re-pack with standard ARJ');
}

Try / catch

try {
  const entries = await readArj(source, options);
} catch (e) {
  if (e instanceof ArchiveError && e.message === 'Invalid ARJ main header') {
    throw new Error('unsupported or malformed ARJ main header; use a standard-compliant archive');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling readArj on an archive whose main header was crafted by a non-standard writer, whose version field is not 2, or whose header size bytes were corrupted after the CRC passed (unlikely) — detected via bytes[bodyStart] and bytes[bodyStart+6].

Common situations: Archives from obscure/buggy ARJ clones, files hand-patched, corruption within the header body, or format variants (e.g. some security-enhanced ARJ versions) not matching the expected layout.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/6cf67f503c36c6ac. Report an issue: GitHub.

Appendix: source

Thrown at packages/utils/src/ar/arj.ts:245

	source: ByteSource,
	options: FormatReadOptions,
): Promise<ArchiveIndexEntry[]> => {
	assertInMemorySize(source.size, options.limits);
	let bytes: Uint8Array;
	try {
		bytes = await readAllBytes(source);
	} catch (error) {
		if (error instanceof ArchiveError) throw error;
		throw new ArchiveError(`Unable to read ARJ archive: ${error instanceof Error ? error.message : String(error)}`);
	}
	if (bytes.byteLength !== source.size) throw new ArchiveError("Invalid ARJ archive: truncated data");
	if (!sniffArj(bytes)) throw new ArchiveError("Invalid ARJ archive header");

	const main = parseArjBlock(bytes, 0, options);
	if (main.isEnd) throw new ArchiveError("Invalid ARJ archive: missing main header");
	const mainFirstHeaderSize = bytes[main.bodyStart]!;
	if (mainFirstHeaderSize < 30 || mainFirstHeaderSize > main.bodySize || bytes[main.bodyStart + 6] !== 2) {
		throw new ArchiveError("Invalid ARJ main header");
	}
	const mainFlags = bytes[main.bodyStart + 4]!;
	if ((mainFlags & 0x01) !== 0) throw new ArchiveError("Encrypted ARJ archives are unsupported");
	if ((mainFlags & 0x04) !== 0) throw new ArchiveError("Multi-volume ARJ archives are unsupported");

	const entries: ArchiveIndexEntry[] = [];
	let offset = main.nextOffset;
	let metadataSize = main.metadataSize;
	let parsedCount = 0;
	for (;;) {
		const block = parseArjBlock(bytes, offset, options);
		metadataSize += block.metadataSize;
		assertIndexSize(metadataSize, options.limits, "index");
		if (block.isEnd) break;
		assertEntryCount(++parsedCount, options.limits);
		const firstHeaderSize = bytes[block.bodyStart]!;
		if (firstHeaderSize < 30 || firstHeaderSize > block.bodySize) throw new ArchiveError("Invalid ARJ local header");
		const hostOs = bytes[block.bodyStart + 3]!;

View on GitHub (pinned to 9690622007)