can1357/oh-my-pi · error · ArchiveError

Invalid ARJ archive: truncated ${what}

Error message

Invalid ARJ archive: truncated ${what}

What it means

assertRange in the ARJ archive reader verifies that a [start, end) byte window lies entirely within the loaded archive bytes. If the offsets are non-integers, negative, inverted, or extend past the buffer, it throws ArchiveError('Invalid ARJ archive: truncated <what>'), where <what> names the structure being read (header signature, basic header, extended header size, local file header, etc.).

Source

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

const LEGACY_DECODER = new TextDecoder("windows-1252");

function u16(bytes: Uint8Array, offset: number): number {
	return bytes[offset]! | (bytes[offset + 1]! << 8);
}

function u32(bytes: Uint8Array, offset: number): number {
	return (bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;
}

function assertRange(bytes: Uint8Array, start: number, end: number, what: string): void {
	if (
		!Number.isSafeInteger(start) ||
		!Number.isSafeInteger(end) ||
		start < 0 ||
		end < start ||
		end > bytes.byteLength
	) {
		throw new ArchiveError(`Invalid ARJ archive: truncated ${what}`);
	}
}

function dosTimeToMs(value: number): number | undefined {
	if (value === 0) return undefined;
	const year = 1980 + ((value >>> 25) & 0x7f);
	const month = (value >>> 21) & 0x0f;
	const day = (value >>> 16) & 0x1f;
	const hour = (value >>> 11) & 0x1f;
	const minute = (value >>> 5) & 0x3f;
	const second = (value & 0x1f) * 2;
	if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) return undefined;
	return Date.UTC(year, month - 1, day, hour, minute, second);
}

function readCString(bytes: Uint8Array, start: number, end: number, field: string): { value: string; next: number } {
	let terminator = start;
	while (terminator < end && bytes[terminator] !== 0) terminator++;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-acquire the archive and verify its size/checksum against the original source.
  2. Check the full file was passed to the reader (not a truncated subarray) and that the download/copy completed.
  3. Validate the archive with an external tool to confirm it is corrupt before deeper debugging.
  4. If the source is a stream, ensure the reader gets all bytes (readAllBytes) rather than a first-chunk buffer.

Example fix

// before
const bytes = (await Bun.file("data.arj").arrayBuffer()).slice(0, 1024); // truncated
readArj(new Uint8Array(bytes));
// after
const bytes = new Uint8Array(await Bun.file("data.arj").arrayBuffer());
try { readArj(bytes); } catch (e) { /* ArchiveError: truncated ... */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if (bytes.byteLength < 4 || bytes[0] !== 0x60 || bytes[1] !== 0xea) {
  throw new Error("Not an ARJ archive (missing 0x60 0xEA signature)");
}

Type guard

function looksLikeArj(bytes: Uint8Array): boolean {
  return bytes.byteLength >= 4 && bytes[0] === 0x60 && bytes[1] === 0xea;
}

Try / catch

import { ArchiveError } from "@oh-my-pi/pi-utils/ar/ar/error";
try {
  return readArj(bytes);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes("truncated")) {
    throw new Error(`ARJ file incomplete (${bytes.byteLength} bytes read); re-download the archive`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling readArj/parseArjBlock on a byte buffer that ends mid-structure: a partially downloaded or copied .arj file, an archive truncated by a failed transfer, a header whose declared size exceeds remaining bytes, or reading from a short buffer where offset arithmetic overruns byteLength.

Common situations: Incomplete FTP/HTTP download of an .arj archive; a file truncated at the source (bad floppy/disk recovery of a DOS-era archive); passing a Uint8Array subarray/slice that cut off the tail; corrupted archive headers with bogus size fields.

Related errors


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