can1357/oh-my-pi · error · ArchiveError

Unable to read ARJ archive: ${error instanceof Error ? error

Error message

Unable to read ARJ archive: ${error instanceof Error ? error.message : String(error)}

What it means

This wrapper ArchiveError is thrown by readArj when reading the archive's bytes from the ByteSource fails with a non-ArchiveError error (I/O failure, permission denied, stream error). The original error message is embedded so the underlying cause is preserved.

Source

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

	if (bytes.byteLength < 34 || bytes[0] !== ARJ_SIGNATURE_0 || bytes[1] !== ARJ_SIGNATURE_1) return false;
	const size = u16(bytes, 2);
	if (size < 30 || size > ARJ_MAX_BASIC_HEADER || bytes.byteLength < size + 8) return false;
	const body = bytes.subarray(4, 4 + size);
	return body[0]! >= 30 && body[0]! <= size && body[6] === 2 && crc32(body) === u32(bytes, 4 + size);
}

/** Index an ARJ archive and lazily decode stored, static-Huffman, and fast-LZSS members. */
export const readArj: FormatReader = async (
	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;

View on GitHub (pinned to 9690622007)

Solutions

  1. Check that the file exists and is readable at the given path before calling readArj.
  2. Inspect the wrapped message (the cause) to identify the underlying I/O error.
  3. Re-mount or restore access to the storage location and retry.
  4. Copy the archive to a local, stable path and read from there.

Example fix

// before
const entries = await readArj({ path, size: stat.size }, options);
// after
try {
  const entries = await readArj({ path, size: stat.size }, options);
} catch (e) {
  if (e instanceof ArchiveError && e.message.startsWith('Unable to read ARJ archive')) {
    throw new Error(`cannot access ${path}: ${e.message}`);
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const stat = await fs.stat(path);
if (!stat.isFile()) throw new Error(`${path} is not a regular file`);
await fs.access(path, fs.constants.R_OK);

Try / catch

try {
  const entries = await readArj(source, options);
} catch (e) {
  if (e instanceof ArchiveError && e.message.startsWith('Unable to read ARJ archive')) {
    // underlying I/O error embedded in message; check file existence/permissions
  } else throw e;
}

Prevention

When it happens

Trigger: Calling readArj(source, options) where readAllBytes(source) rejects with a filesystem or network error — e.g. the file was deleted mid-read, read permission is missing, or a remote stream errored.

Common situations: Files on unmounted/network drives, permissions changed between stat and read, deleted temp files, storage device errors.

Related errors


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