{"record":{"id":"cf736d7639680149","repo":"can1357/oh-my-pi","slug":"rar-member-memberpath-size-mismatch-bytes","errorCode":null,"errorMessage":"RAR member '${memberPath}' size mismatch (${bytes.byteLength} != ${size})","messagePattern":"RAR member '(.+?)' size mismatch \\((.+?) != (.+?)\\)","errorType":"validation","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/rar.ts","lineNumber":75,"sourceCode":"\t\tthis.#source = source;\n\t\tthis.#records = records;\n\t\tthis.#limits = options.limits;\n\t}\n\n\tmember(index: number): MemberSource {\n\t\treturn new RarMemberSource(this, index);\n\t}\n\n\tasync read(index: number, size: number, memberPath: string): Promise<Uint8Array> {\n\t\tconst pending = this.#queue.then(async () => {\n\t\t\tif (!this.#cache.has(index)) await this.#decode(index);\n\t\t});\n\t\tthis.#queue = pending.catch(() => undefined);\n\t\tawait pending;\n\t\tconst bytes = this.#cache.get(index);\n\t\tif (!bytes) throw new ArchiveError(`Failed to extract RAR member '${memberPath}'`);\n\t\tif (bytes.byteLength !== size) {\n\t\t\tthrow new ArchiveError(`RAR member '${memberPath}' size mismatch (${bytes.byteLength} != ${size})`);\n\t\t}\n\t\treturn bytes.slice();\n\t}\n\n\tasync #decode(index: number): Promise<void> {\n\t\tconst target = this.#records[index];\n\t\tif (!target) throw new ArchiveError(\"Invalid RAR member index\");\n\t\tlet start = index;\n\t\tif (target.solid) {\n\t\t\twhile (start > 0 && this.#records[start]!.solid && this.#records[start - 1]!.format === target.format) start--;\n\t\t}\n\t\tconst rar4Decoder = new Rar4Decoder();\n\t\tconst rar5Decoder = new Rar5Decoder();\n\t\tfor (let current = start; current <= index; current++) {\n\t\t\tconst record = this.#records[current]!;\n\t\t\tif (record.isDirectory) continue;\n\t\t\tassertArchiveMemberSize(record.unpackedSize, record.path, this.#limits);\n\t\t\tif (record.method === 0 && record.packedSize !== record.unpackedSize) {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/rar.ts#L57-L93","documentation":"After successful decode, the extracted byte length is compared against the unpackedSize recorded in the member's header. A mismatch means the decoder produced a different number of bytes than the archive metadata promised, so the result cannot be trusted and read() throws.","triggerScenarios":"read(memberPath) on a member whose decoded output length differs from the declared unpacked size — typically from a corrupt compressed stream, a decoder bug, or metadata tampering.","commonSituations":"Truncated or bit-rotted archives where the stream decodes 'successfully' but short/long; archives edited by third-party tools that wrote inconsistent headers.","solutions":["Run `unrar t archive.rar` to confirm corruption and re-obtain the archive","Re-download the archive; check the source storage for disk errors","If you created the archive, re-create it with current WinRAR/rar tooling"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const bytes = await reader.read(memberPath);\n} catch (err) {\n  if (err instanceof ArchiveError && /size mismatch/.test(err.message)) {\n    // treat archive as corrupt: re-fetch or recover via unrar\n  }\n  throw err;\n}","preventionTips":["Check archive integrity (CRC test) before extracting members","Keep archives on healthy storage; re-download files from unreliable sources","Never mutate member headers with third-party tools before extraction"],"tags":["rar","archive","size-mismatch","integrity"],"backgroundTag":"archive-member-size-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}