can1357/oh-my-pi · error · ArchiveError
Encrypted ARJ archives are unsupported
Error message
Encrypted ARJ archives are unsupported
What it means
The ARJ reader in readArj validates the flags byte of the archive's main (archive) header. Bit 0 (0x01) of that byte marks the entire archive as password-encrypted. This library does not implement ARJ decryption, so it refuses the archive up front instead of producing unreadable members.
Source
Thrown at packages/utils/src/ar/arj.ts:248
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]!;
const flags = bytes[block.bodyStart + 4]!;
const method = bytes[block.bodyStart + 5]!;
const fileType = bytes[block.bodyStart + 6]!;View on GitHub (pinned to 9690622007)
Solutions
- Decrypt the archive with the original ARJ tooling (arj x -g<password>) or an external tool, then feed the plaintext archive to the library.
- Obtain the password from the archive's source and pre-process it out of band; this library will not decrypt.
- If encrypted archives are expected, detect this error and route to a pipeline/tool that supports ARJ encryption, or reject the input earlier with your own pre-check.
- If the archive is NOT actually sensitive and you control creation, regenerate it without the password option.
Example fix
// before
const entries = await readArj(source, options); // throws on password-protected ARJ
// after
if (!hasArjPassword(source)) {
const entries = await readArj(source, options);
} else {
const plain = await decryptArjExternally(source, password);
const entries = await readArj(plain, options);
} Defensive patterns
Strategy: validation
Validate before calling
function isArjEncrypted(bytes: Uint8Array): boolean {
// main header located by the same walk readArj performs; at bodyStart:
// byte 4 is the flags byte, bit 0x01 = encrypted archive
const flags = bytes[mainHeaderBodyStart(bytes) + 4] ?? 0;
return (flags & 0x01) !== 0;
}
if (isArjEncrypted(bytes)) throw new Error("Rejecting password-protected ARJ before parse"); Type guard
function isPlaintextArjFlags(flags: number): boolean {
return (flags & 0x01) === 0;
} Try / catch
try {
entries = await readArj(source, options);
} catch (e) {
if (e instanceof ArchiveError && e.message === "Encrypted ARJ archives are unsupported") {
return { status: "needs-external-decrypt", archive: path };
}
throw e;
} Prevention
- Pre-scan the ARJ main header flags byte before parsing and reject encrypted inputs in your ingest pipeline.
- Document to archive producers that password-protected ARJ files are not accepted.
- Keep the decryption step (external ARJ tool) as an explicit, separate pipeline stage with password management.
When it happens
Trigger: readArj (the ARJ FormatReader) is called on a buffer whose main header at bodyStart has flags byte (bytes[bodyStart+4]) with bit 0x01 set — i.e. an ARJ archive created with a password ('-g' password option in ARJ tooling).
Common situations: Processing legacy ARJ archives that were password-protected for distribution; archives shared with the password communicated out-of-band (email, chat) that the caller never supplied; automated ingest of old shareware-era archives.
Related errors
- Encrypted ARJ members are unsupported
- ARJ member '${memberPath}' uses unsupported compression meth
- Multi-volume ARJ archives are unsupported
- Multi-volume ARJ members are unsupported
- Invalid ARJ archive: truncated ${what}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/dec7ab12d56eb10a.
Report an issue: GitHub.