can1357/oh-my-pi · error · ArchiveError

ASAR member path '${memberPath}' crosses file '${parts.slice

Error message

ASAR member path '${memberPath}' crosses file '${parts.slice(0, index + 1).join("/")}'

What it means

encodeAsar builds a tree of directories from member paths; this error fires when a path needs an intermediate segment (e.g. 'a/b.txt') but that segment was already registered as a FILE by an earlier member (e.g. 'a'). ASAR nodes cannot be both a file and a directory, so the library refuses to silently overwrite. It is a conflict between two member paths in the same encode call.

Source

Thrown at packages/utils/src/ar/asar.ts:426

		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)!;
			if (directory.files[name]) {
				throw new ArchiveError(`Duplicate or conflicting ASAR member path '${memberPath}'`);
			}
			if (!Number.isSafeInteger(member[1].byteLength) || !Number.isSafeInteger(payloadSize + member[1].byteLength)) {
				throw new ArchiveError("ASAR payload is too large to encode safely");
			}
			directory.files[name] = { size: member[1].byteLength, offset: String(payloadSize) };
			payloads.push(member[1]);
			payloadSize += member[1].byteLength;

View on GitHub (pinned to 9690622007)

Solutions

  1. Deduplicate/validate member paths before encoding: reject any path that is a strict prefix (directory-wise) of another path.
  2. Decide which node is correct — if 'assets' was meant to be a directory, don't add it as a file member; if it's a file, rename the nested entries.
  3. Normalize path separators before building the member list so 'a\b' and 'a/b' don't produce conflicting shapes.
  4. Wrap the encodeAsar call in try/catch for ArchiveError and surface the two offending paths to the user.

Example fix

// before
members.push(['assets', fileBytes]);
members.push(['assets/logo.png', logoBytes]); // throws: crosses file 'assets'
// after
members.push(['assets/logo.png', logoBytes]); // drop the bare 'assets' file member, or nest the file as 'assets/_self'
Defensive patterns

Strategy: validation

Validate before calling

function isPrefixConflict(members) {
  const files = new Set(members.map(([p]) => p.replace(/\\/g, '/')));
  for (const p of files) {
    const parts = p.split('/');
    for (let i = 1; i < parts.length; i++) {
      if (files.has(parts.slice(0, i).join('/'))) return `${parts.slice(0, i).join('/')}`;
    }
  }
  return null;
}
const conflict = isPrefixConflict(members);
if (conflict) throw new Error(`member '${conflict}' is both a file and a directory`);

Try / catch

try {
  const archive = await encodeAsar(members);
} catch (err) {
  if (err instanceof ArchiveError && err.message.includes('crosses file')) {
    throw new Error(`Conflicting ASAR paths: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling encodeAsar (directly or via encodeArchive/bytes) with two members whose paths collide at an intermediate segment: one member is a prefix-path of another, e.g. ['assets', data1] plus ['assets/logo.png', data2]. The second member's directory walk hits 'assets', finds a file node instead of a directory, and throws.

Common situations: Globbing directories that collect both files and their parent paths as entries; merging member lists from multiple sources where one treats 'assets' as a file and another nests content under 'assets/'; backslash-vs-slash normalization making 'a\b' and 'a/b' look distinct to the caller but collapse to the same tree in the writer.

Related errors


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