{"record":{"id":"bb25002b7f442e59","repo":"can1357/oh-my-pi","slug":"asar-member-formatarchivepathforerror-memberpat-bb2500","errorCode":null,"errorMessage":"ASAR member '${formatArchivePathForError(memberPath)}' has an inconsistent size","messagePattern":"ASAR member '(.+?)' has an inconsistent size","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/asar.ts","lineNumber":117,"sourceCode":"\t}\n}\n\nclass PackedAsarMemberSource implements MemberSource {\n\treadonly #source: ByteSource;\n\treadonly #offset: number;\n\treadonly #size: number;\n\treadonly #integrity?: AsarIntegrity;\n\n\tconstructor(source: ByteSource, offset: number, size: number, integrity: AsarIntegrity | undefined) {\n\t\tthis.#source = source;\n\t\tthis.#offset = offset;\n\t\tthis.#size = size;\n\t\tthis.#integrity = integrity;\n\t}\n\n\tasync read(size: number, memberPath: string): Promise<Uint8Array> {\n\t\tif (size !== this.#size) {\n\t\t\tthrow new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' has an inconsistent size`);\n\t\t}\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = await this.#source.read(this.#offset, this.#offset + this.#size);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ArchiveError) throw error;\n\t\t\tthrow new ArchiveError(\n\t\t\t\t`Failed to read ASAR member '${formatArchivePathForError(memberPath)}': ${describeError(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (bytes.byteLength !== this.#size) {\n\t\t\tthrow new ArchiveError(`ASAR member '${formatArchivePathForError(memberPath)}' is truncated`);\n\t\t}\n\t\tverifyIntegrity(bytes, this.#integrity, memberPath);\n\t\treturn bytes;\n\t}\n}\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/asar.ts#L99-L135","documentation":"The packed ASAR member source records the member's size from the archive header. When read(size, memberPath) is called with a requested size that differs from the header-recorded size, the internal offsets and the caller's expectation disagree — the caller would read the wrong byte range — so the reader refuses rather than returning wrong data.","triggerScenarios":"read() on a PackedAsarMemberSource with the size argument (derived by the caller from a pickle/header length field) not equal to the member's #size recorded in the ASAR header — inconsistent size pickles or a caller using the wrong length source.","commonSituations":"Hand-crafted or third-party-written ASAR files where the size pickle and header entry disagree; bugs in code that manually parses the ASAR header and passes the wrong length; corruption of the size fields.","solutions":["Regenerate the ASAR with the official asar tool so header sizes and pickles are consistent.","Audit any custom ASAR-parsing code: the size passed to read must come from the same header entry (offset+size pair), not a separately parsed pickle.","Validate the archive structurally (header pickle sizes vs. member entries) before reading members and reject inconsistent files early.","Verify the file is not truncated/corrupted by comparing whole-file size against the header's expected total."],"exampleFix":"// before\nconst bytes = await source.read(someOtherLength, path); // mismatch → throws\n// after\nconst entry = headerEntryFor(path);\nconst bytes = await source.read(entry.size, path); // always the header-recorded size","handlingStrategy":"validation","validationCode":"// Before reading, confirm every member's size pickle and header entry agree.\nfunction assertAsarSizesConsistent(header: AsarHeader): void {\n\tfor (const [p, entry] of Object.entries(header.files)) {\n\t\tif (!Number.isSafeInteger(entry.size) || entry.size < 0 || entry.offset + entry.size > header.totalSize) {\n\t\t\tthrow new Error(`ASAR header entry for '${p}' has an inconsistent size`);\n\t\t}\n\t}\n}","typeGuard":"function hasConsistentMemberSize(entry: { offset: number; size: number }, totalSize: number): boolean {\n\treturn Number.isSafeInteger(entry.size) && entry.size >= 0 && entry.offset + entry.size <= totalSize;\n}","tryCatchPattern":"try {\n\tconst bytes = await member.read(size, path);\n} catch (e) {\n\tif (e instanceof ArchiveError && e.message.includes(\"has an inconsistent size\")) {\n\t\tthrow new Error(`ASAR header/data out of sync for '${path}'; repack the archive`);\n\t}\n\tthrow e;\n}","preventionTips":["Always take member sizes from the parsed ASAR header entry, never from a separately parsed pickle or hardcoded value.","Repack with the official asar tool rather than hand-editing ASAR bytes.","Structurally validate header entries (offset+size within file bounds) before reading members."],"tags":["archive","asar","size-mismatch","validation"],"backgroundTag":"size-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}