can1357/oh-my-pi · error · ArchiveError
Invalid ARJ header signature
Error message
Invalid ARJ header signature
What it means
Every ARJ file begins with the two-byte magic 0x60 0xEA followed by a 16-bit header size. parseArjBlock checks these first two bytes before reading anything else; a mismatch means the data is not an ARJ archive (or the reader's offset is wrong), so it throws immediately rather than misparsing random bytes.
Source
Thrown at packages/utils/src/ar/arj.ts:64
function readCString(bytes: Uint8Array, start: number, end: number, field: string): { value: string; next: number } {
let terminator = start;
while (terminator < end && bytes[terminator] !== 0) terminator++;
if (terminator === end) throw new ArchiveError(`Invalid ARJ ${field}: missing terminator`);
return { value: LEGACY_DECODER.decode(bytes.subarray(start, terminator)), next: terminator + 1 };
}
interface ArjBlock {
bodyStart: number;
bodySize: number;
nextOffset: number;
metadataSize: number;
isEnd: boolean;
}
function parseArjBlock(bytes: Uint8Array, offset: number, options: FormatReadOptions): ArjBlock {
assertRange(bytes, offset, offset + 4, "header signature");
if (bytes[offset] !== ARJ_SIGNATURE_0 || bytes[offset + 1] !== ARJ_SIGNATURE_1) {
throw new ArchiveError("Invalid ARJ header signature");
}
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;View on GitHub (pinned to 9690622007)
Solutions
- Inspect the first bytes: run `xxd -l 16 file.arj` and confirm they are `60 ea`. If not, the file is not ARJ.
- Identify the real format (`file file.arj`) and use the matching reader in this library (zip/tar/lzh readers) instead of the ARJ one.
- Re-download or re-extract the archive; a corrupted first sector produces exactly this failure.
- If you drive parseArjBlock yourself, make sure the offset is a real block start (offsets come from previous parseArjBlock results, never manual arithmetic).
Example fix
// before: blindly parsing whatever the user supplied
const entries = readArj(userUpload);
// after: verify the magic before parsing
const head = new Uint8Array(userUpload.slice(0, 2));
if (head[0] !== 0x60 || head[1] !== 0xea) {
throw new Error("Not an ARJ archive: bad magic (expected 60 EA)");
}
const entries = readArj(userUpload); Defensive patterns
Strategy: validation
Validate before calling
function isArjMagic(bytes: Uint8Array): boolean {
return bytes.byteLength >= 2 && bytes[0] === 0x60 && bytes[1] === 0xea;
}
if (!isArjMagic(data)) throw new Error("Not an ARJ archive: bad magic bytes"); Type guard
function isArjBuffer(data: unknown): data is Uint8Array {
return data instanceof Uint8Array && data.byteLength >= 2 && data[0] === 0x60 && data[1] === 0xea;
} Try / catch
try {
return readArj(data);
} catch (err) {
if (err instanceof ArchiveError && err.message === "Invalid ARJ header signature") {
throw new Error("Input is not an ARJ archive (missing 60 EA signature)");
}
throw err;
} Prevention
- Sniff magic bytes (60 EA) or use `file` output to route files to the correct format reader before calling readArj.
- Never assume file extensions are accurate; verify content signatures.
- Strip any transport wrappers (HTTP headers, concatenated scripts) before parsing.
When it happens
Trigger: Calling readArj()/parseArjBlock() at an offset whose first two bytes are not 0x60 0xEA: a non-ARJ file passed to the reader, reading past the last local header block with a wrong end-of-archive detection, or an offset/desync bug in custom seeking code.
Common situations: Wrong file extension (e.g. a .zip or .exe renamed .arj), a text editor or download manager that altered/trimmed the file, pointing the reader at the wrong offset after hand-editing an index, or passing a Buffer that includes an HTTP header prepended to the archive.
Related errors
- Invalid tar octal value: ${value}
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ basic header size
- Invalid ARJ archive header
- Invalid XZ stream: footer magic mismatch
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/56b261ce207af929.
Report an issue: GitHub.