can1357/oh-my-pi · error · ArchiveError
Encrypted ARJ members are unsupported
Error message
Encrypted ARJ members are unsupported
What it means
Bit 0 (0x01) of an ARJ local file header's flags byte marks that individual member as encrypted with a password. Since the library implements no ARJ decryption, it refuses to index archives containing encrypted members. This is the per-file counterpart to the main-header encryption check.
Source
Thrown at packages/utils/src/ar/arj.ts:267
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]!;
if ((flags & 0x01) !== 0) throw new ArchiveError("Encrypted ARJ members are unsupported");
if ((flags & 0x0c) !== 0) throw new ArchiveError("Multi-volume ARJ members are unsupported");
const packedSize = u32(bytes, block.bodyStart + 12);
const size = u32(bytes, block.bodyStart + 16);
const fileCrc = u32(bytes, block.bodyStart + 20);
const accessMode = u16(bytes, block.bodyStart + 26);
const filename = readCString(
bytes,
block.bodyStart + firstHeaderSize,
block.bodyStart + block.bodySize,
"filename",
);
readCString(bytes, filename.next, block.bodyStart + block.bodySize, "comment");
assertArchivePathBytes(
filename.next - (block.bodyStart + firstHeaderSize) - 1,
"member path",
options.limits.maxPathBytes,
);
const rawPath = normalizeHostPath(filename.value, hostOs);View on GitHub (pinned to 9690622007)
Solutions
- Decrypt the archive externally with the original password (arj x -g<password>), then index the plaintext result.
- Ask the archive producer to re-create it without per-member encryption if the content is not actually secret.
- If partial extraction is acceptable, pre-scan headers yourself and remove/replace the encrypted members before calling readArj.
- Route encrypted-member archives to a tool that supports ARJ crypto and handle its output instead.
Example fix
// before const entries = await readArj(bytes, options); // throws on any encrypted member // after const plain = await decryptArjMembers(bytes, password); // external tool const entries = await readArj(plain, options);
Defensive patterns
Strategy: validation
Validate before calling
// Pre-scan local headers the same way readArj does; stop before parsing member data.
function hasEncryptedArjMembers(bytes: Uint8Array): boolean {
// walk blocks; for each non-end block check (bytes[block.bodyStart + 4] & 0x01) !== 0
return scanArjLocalFlags(bytes).some((flags) => (flags & 0x01) !== 0);
}
if (hasEncryptedArjMembers(bytes)) throw new Error("ARJ contains encrypted members; decrypt externally first"); Type guard
function isUnencryptedArjMemberFlags(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 members are unsupported") {
return { status: "encrypted-member", hint: "decrypt with the original password via ARJ tooling" };
}
throw e;
} Prevention
- Request unencrypted archives, or obtain the password and decrypt externally before ingest.
- Pre-scan member flags in your pipeline to catch encrypted members before the parser does.
- Keep passwords in a secret store, never embedded in pipeline code.
When it happens
Trigger: readArj parses a local header whose flags byte (bytes[bodyStart+4]) has 0x01 set — the member was stored with ARJ's per-file password ('-g' when adding files).
Common situations: Archives where only some files (e.g. secrets, license keys) were password-protected while the rest are plain; mixed archives assembled from multiple sources.
Related errors
- Encrypted ARJ archives 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/078ba13e926f7d77.
Report an issue: GitHub.