{"record":{"id":"078ba13e926f7d77","repo":"can1357/oh-my-pi","slug":"encrypted-arj-members-are-unsupported","errorCode":null,"errorMessage":"Encrypted ARJ members are unsupported","messagePattern":"Encrypted ARJ members are unsupported","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/arj.ts","lineNumber":267,"sourceCode":"\tif ((mainFlags & 0x04) !== 0) throw new ArchiveError(\"Multi-volume ARJ archives are unsupported\");\n\n\tconst entries: ArchiveIndexEntry[] = [];\n\tlet offset = main.nextOffset;\n\tlet metadataSize = main.metadataSize;\n\tlet parsedCount = 0;\n\tfor (;;) {\n\t\tconst block = parseArjBlock(bytes, offset, options);\n\t\tmetadataSize += block.metadataSize;\n\t\tassertIndexSize(metadataSize, options.limits, \"index\");\n\t\tif (block.isEnd) break;\n\t\tassertEntryCount(++parsedCount, options.limits);\n\t\tconst firstHeaderSize = bytes[block.bodyStart]!;\n\t\tif (firstHeaderSize < 30 || firstHeaderSize > block.bodySize) throw new ArchiveError(\"Invalid ARJ local header\");\n\t\tconst hostOs = bytes[block.bodyStart + 3]!;\n\t\tconst flags = bytes[block.bodyStart + 4]!;\n\t\tconst method = bytes[block.bodyStart + 5]!;\n\t\tconst fileType = bytes[block.bodyStart + 6]!;\n\t\tif ((flags & 0x01) !== 0) throw new ArchiveError(\"Encrypted ARJ members are unsupported\");\n\t\tif ((flags & 0x0c) !== 0) throw new ArchiveError(\"Multi-volume ARJ members are unsupported\");\n\t\tconst packedSize = u32(bytes, block.bodyStart + 12);\n\t\tconst size = u32(bytes, block.bodyStart + 16);\n\t\tconst fileCrc = u32(bytes, block.bodyStart + 20);\n\t\tconst accessMode = u16(bytes, block.bodyStart + 26);\n\t\tconst filename = readCString(\n\t\t\tbytes,\n\t\t\tblock.bodyStart + firstHeaderSize,\n\t\t\tblock.bodyStart + block.bodySize,\n\t\t\t\"filename\",\n\t\t);\n\t\treadCString(bytes, filename.next, block.bodyStart + block.bodySize, \"comment\");\n\t\tassertArchivePathBytes(\n\t\t\tfilename.next - (block.bodyStart + firstHeaderSize) - 1,\n\t\t\t\"member path\",\n\t\t\toptions.limits.maxPathBytes,\n\t\t);\n\t\tconst rawPath = normalizeHostPath(filename.value, hostOs);","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/arj.ts#L249-L285","documentation":"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.","triggerScenarios":"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).","commonSituations":"Archives where only some files (e.g. secrets, license keys) were password-protected while the rest are plain; mixed archives assembled from multiple sources.","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."],"exampleFix":"// before\nconst entries = await readArj(bytes, options); // throws on any encrypted member\n// after\nconst plain = await decryptArjMembers(bytes, password); // external tool\nconst entries = await readArj(plain, options);","handlingStrategy":"validation","validationCode":"// Pre-scan local headers the same way readArj does; stop before parsing member data.\nfunction hasEncryptedArjMembers(bytes: Uint8Array): boolean {\n\t// walk blocks; for each non-end block check (bytes[block.bodyStart + 4] & 0x01) !== 0\n\treturn scanArjLocalFlags(bytes).some((flags) => (flags & 0x01) !== 0);\n}\nif (hasEncryptedArjMembers(bytes)) throw new Error(\"ARJ contains encrypted members; decrypt externally first\");","typeGuard":"function isUnencryptedArjMemberFlags(flags: number): boolean {\n\treturn (flags & 0x01) === 0;\n}","tryCatchPattern":"try {\n\tentries = await readArj(source, options);\n} catch (e) {\n\tif (e instanceof ArchiveError && e.message === \"Encrypted ARJ members are unsupported\") {\n\t\treturn { status: \"encrypted-member\", hint: \"decrypt with the original password via ARJ tooling\" };\n\t}\n\tthrow e;\n}","preventionTips":["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."],"tags":["archive","arj","encryption","unsupported-feature"],"backgroundTag":"encrypted-archive-unsupported","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}