{"record":{"id":"207fb30bdc8c2cf9","repo":"can1357/oh-my-pi","slug":"multi-volume-arj-members-are-unsupported","errorCode":null,"errorMessage":"Multi-volume ARJ members are unsupported","messagePattern":"Multi-volume ARJ members are unsupported","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/arj.ts","lineNumber":268,"sourceCode":"\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);\n\t\tassertArchivePathString(rawPath, \"member path\", options.limits.maxPathBytes);","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/arj.ts#L250-L286","documentation":"Bits 2-3 (0x0c) of an ARJ local file header's flags byte mark the member as part of a multi-volume sequence (continued on another volume, in various directions). The single-buffer reader cannot assemble members spanning volumes, so it rejects archives containing such members.","triggerScenarios":"readArj parses a local header whose flags byte has any of 0x04 or 0x08 set — the member's data continues on the next/previous volume of a split archive.","commonSituations":"Members split across .arj/.a01/.a02 volumes of a floppy-era backup; indexing only the first volume while the member actually spans volumes.","solutions":["Extract the complete volume set with the original ARJ tool (all .arj/.aNN files present) and index the extracted files or the re-merged single archive.","Reject multi-volume inputs in your pipeline before parsing by pre-checking the main header flags (0x04) and member flags.","Repackage the data as a single-volume archive if you control the source.","Use an external ARJ-compatible extractor that supports volumes, then hand the plain files to this library's other readers if applicable."],"exampleFix":"// before\nconst entries = await readArj(volume1Bytes, options); // throws on spanning member\n// after\nif (hasArjVolumeFlags(volume1Bytes)) {\n  const files = await extractAllVolumesWithArjTool(volumeDir);\n  // index extracted plain files instead\n}","handlingStrategy":"validation","validationCode":"function hasArjVolumeMembers(bytes: Uint8Array): boolean {\n\treturn scanArjLocalFlags(bytes).some((flags) => (flags & 0x0c) !== 0);\n}\nif (hasArjVolumeMembers(bytes)) throw new Error(\"ARJ members span volumes; extract the full set first\");","typeGuard":"function isSingleVolumeArjMemberFlags(flags: number): boolean {\n\treturn (flags & 0x0c) === 0;\n}","tryCatchPattern":"try {\n\tentries = await readArj(source, options);\n} catch (e) {\n\tif (e instanceof ArchiveError && e.message === \"Multi-volume ARJ members are unsupported\") {\n\t\treturn { status: \"multi-volume-member\", hint: \"extract all volumes with the ARJ tool, then index the output\" };\n\t}\n\tthrow e;\n}","preventionTips":["Reject split archives at ingest (main header flag 0x04 is a cheap early signal).","Ensure the complete volume set accompanies any multi-volume ARJ before processing.","Repackage legacy split backups into single archives during migration."],"tags":["archive","arj","multi-volume","unsupported-feature"],"backgroundTag":"multivolume-archive-unsupported","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}