can1357/oh-my-pi · error · ArchiveError
ASAR members must be [path, Uint8Array] pairs
Error message
ASAR members must be [path, Uint8Array] pairs
What it means
Thrown by encodeAsar when an item yielded by the members iterable is not a [string, Uint8Array] tuple: not an array, wrong length, non-string path, or non-Uint8Array payload. It is an input-shape contract check before any path validation.
Source
Thrown at packages/utils/src/ar/asar.ts:417
throw new ArchiveError(`Invalid ASAR member path '${formatArchivePathForError(rawPath)}'`);
}
return normalized;
}
/** Encode file members in Electron's Pickle-framed ASAR layout. */
export async function encodeAsar(members: Iterable<readonly [string, Uint8Array]>): Promise<Uint8Array> {
try {
const root: AsarDirectoryNode = { files: Object.create(null) as Record<string, AsarNode> };
const payloads: Uint8Array[] = [];
let payloadSize = 0;
for (const member of members) {
if (
!Array.isArray(member) ||
member.length !== 2 ||
typeof member[0] !== "string" ||
!(member[1] instanceof Uint8Array)
) {
throw new ArchiveError("ASAR members must be [path, Uint8Array] pairs");
}
const memberPath = writerPath(member[0]);
const parts = memberPath.split("/");
let directory = root;
for (let index = 0; index < parts.length - 1; index++) {
const part = parts[index]!;
const existing = directory.files[part];
if (existing && !("files" in existing)) {
throw new ArchiveError(
`ASAR member path '${memberPath}' crosses file '${parts.slice(0, index + 1).join("/")}'`,
);
}
if (!existing) {
directory.files[part] = { files: Object.create(null) as Record<string, AsarNode> };
}
directory = directory.files[part] as AsarDirectoryNode;
}
const name = parts.at(-1)!;View on GitHub (pinned to 9690622007)
Solutions
- Ensure every member is exactly a 2-tuple: [relativePath: string, payload: Uint8Array]
- Convert string payloads with new TextEncoder().encode(text) and ArrayBuffer with new Uint8Array(buf)
- If input is object-shaped, map it to tuples: Object.entries(map).map(([p, d]) => [p, d])
Example fix
// before
encodeAsar([{ path: "a.txt", data: "hello" }])
// after
encodeAsar([["a.txt", new TextEncoder().encode("hello")]]) Defensive patterns
Strategy: type-guard
Validate before calling
const toMembers = (input) => Object.entries(input).map(([p, d]) => [p, d instanceof Uint8Array ? d : new TextEncoder().encode(String(d))]);
Type guard
const isAsarMember = (m) => Array.isArray(m) && m.length === 2 && typeof m[0] === "string" && m[1] instanceof Uint8Array;
Try / catch
try { return await encodeAsar(rawMembers); } catch (e) { if (e instanceof ArchiveError && e.message.includes("must be [path, Uint8Array] pairs")) { console.error("normalize member tuples before encoding"); } throw e; } Prevention
- Encode string contents with TextEncoder before passing to encodeAsar
- Keep member collections as [string, Uint8Array] tuples end to end
- Type the input as Iterable<readonly [string, Uint8Array]> so TS catches mistakes at compile time
When it happens
Trigger: Passing objects instead of tuples ({path, data}), 3-element arrays, Node Buffer is fine only if it's a Uint8Array subclass (it is), but strings/ArrayBuffers/blob handles as payloads are rejected; iterables of Maps or entries from Object.entries with reordered fields.
Common situations: Collecting files with an async mapper that accidentally returns [path, string] after text decoding; passing PathOrFileRecord-style objects; TypeScript code compiled loosely at runtime boundaries (JSON-parsed input).
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- vault:// path resolution only supports plain filesystem path
- ${label} must be a string
- ${label} must be a boolean
- ${label} must be a finite number
- ${label} must be an array of strings
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a4a737ce56ea10b6.
Report an issue: GitHub.