{"record":{"id":"8de7e9a9ac4e9c55","repo":"can1357/oh-my-pi","slug":"invalid-arj-basic-header-crc32","errorCode":null,"errorMessage":"Invalid ARJ basic header CRC32","messagePattern":"Invalid ARJ basic header CRC32","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/arj.ts","lineNumber":74,"sourceCode":"\tnextOffset: number;\n\tmetadataSize: number;\n\tisEnd: boolean;\n}\n\nfunction parseArjBlock(bytes: Uint8Array, offset: number, options: FormatReadOptions): ArjBlock {\n\tassertRange(bytes, offset, offset + 4, \"header signature\");\n\tif (bytes[offset] !== ARJ_SIGNATURE_0 || bytes[offset + 1] !== ARJ_SIGNATURE_1) {\n\t\tthrow new ArchiveError(\"Invalid ARJ header signature\");\n\t}\n\tconst bodySize = u16(bytes, offset + 2);\n\tif (bodySize === 0)\n\t\treturn { bodyStart: offset + 4, bodySize: 0, nextOffset: offset + 4, metadataSize: 4, isEnd: true };\n\tif (bodySize < 30 || bodySize > ARJ_MAX_BASIC_HEADER) throw new ArchiveError(\"Invalid ARJ basic header size\");\n\tconst bodyStart = offset + 4;\n\tconst bodyEnd = bodyStart + bodySize;\n\tassertRange(bytes, bodyStart, bodyEnd + 4, \"basic header\");\n\tif (crc32(bytes.subarray(bodyStart, bodyEnd)) !== u32(bytes, bodyEnd)) {\n\t\tthrow new ArchiveError(\"Invalid ARJ basic header CRC32\");\n\t}\n\tlet cursor = bodyEnd + 4;\n\tlet extensionCount = 0;\n\tfor (;;) {\n\t\tassertRange(bytes, cursor, cursor + 2, \"extended header size\");\n\t\tconst extensionSize = u16(bytes, cursor);\n\t\tcursor += 2;\n\t\tif (extensionSize === 0) break;\n\t\tif (++extensionCount > 65_535) throw new ArchiveError(\"Invalid ARJ archive: too many extended headers\");\n\t\tassertRange(bytes, cursor, cursor + extensionSize + 4, \"extended header\");\n\t\tif (crc32(bytes.subarray(cursor, cursor + extensionSize)) !== u32(bytes, cursor + extensionSize)) {\n\t\t\tthrow new ArchiveError(\"Invalid ARJ extended header CRC32\");\n\t\t}\n\t\tcursor += extensionSize + 4;\n\t\tassertIndexSize(cursor - offset, options.limits, \"header metadata\");\n\t}\n\treturn { bodyStart, bodySize, nextOffset: cursor, metadataSize: cursor - offset, isEnd: false };\n}","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/arj.ts#L56-L92","documentation":"ARJ basic headers end with a CRC-32 over the header body, stored immediately after it. parseArjBlock computes crc32 over bytes [bodyStart, bodyEnd) and compares it with the little-endian u32 at bodyEnd. A mismatch means the header bytes were altered or misread, so the parser stops rather than trusting corrupted metadata (names, sizes, timestamps).","triggerScenarios":"Any single-bit or multi-byte change inside the basic header body, or the size field being wrong so bodyStart/bodyEnd are shifted and a different region is hashed. Thrown from parseArjBlock after assertRange passes.","commonSituations":"Damaged downloads or media errors, an in-place file edit (e.g. someone patched a stored filename by hand), transmission through a channel that altered bytes (FTP ASCII mode on old tooling), or a generator that writes headers without computing the CRC.","solutions":["Verify the archive externally (`arj t archive.arj`, 7-Zip test) to confirm corruption, then restore from a known-good copy.","If the file was transferred, re-transfer in binary mode and compare checksums (sha256sum) between source and destination.","If you generate ARJ files, ensure you CRC-32 the header body and append it little-endian; test with a reference reader.","Never hand-edit ARJ header bytes (filenames, flags) without recomputing the stored CRC-32."],"exampleFix":"// before: editing the header body in place without fixing the CRC\nbytes.set(newNameBytes, nameOffset);\n// after: rebuild the header, recompute CRC-32, and rewrite both body and CRC\nbytes.set(newNameBytes, nameOffset);\nconst crc = crc32(bytes.subarray(bodyStart, bodyEnd));\nnew DataView(bytes.buffer).setUint32(bodyEnd, crc, true);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return readArj(data, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes(\"basic header CRC32\")) {\n    // corrupt header — quarantine the file, do not attempt partial extraction\n    logger.error(\"ARJ basic header CRC mismatch\", { size: data.byteLength });\n    return null;\n  }\n  throw err;\n}","preventionTips":["Always transfer archives in binary mode; verify checksums end-to-end.","Never hand-edit header bytes without recomputing the CRC-32.","Run an external integrity test before processing user-supplied archives."],"tags":["archive","checksum","crc32","corrupt-file"],"backgroundTag":"archive-checksum-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}