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

  1. Ensure every member is exactly a 2-tuple: [relativePath: string, payload: Uint8Array]
  2. Convert string payloads with new TextEncoder().encode(text) and ArrayBuffer with new Uint8Array(buf)
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/a4a737ce56ea10b6. Report an issue: GitHub.