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
- Deduplicate/validate member paths before encoding: reject any path that is a strict prefix (directory-wise) of another path.
- 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.
- Normalize path separators before building the member list so 'a\b' and 'a/b' don't produce conflicting shapes.
- 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
- Normalize backslashes to forward slashes before building member lists.
- Reject any member path that is a directory prefix of another member before encoding.
- Deduplicate members through a Map keyed by normalized path.
- Keep glob patterns non-overlapping when collecting files.
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
- ASAR member '${formatArchivePathForError(memberPath)}' has a
- Duplicate or conflicting ASAR member path '${memberPath}'
- Invalid ARJ ${field}: missing terminator
- Invalid ARJ local header
- Invalid ARJ archive: no members
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/2ceb1cc98c973c7c.
Report an issue: GitHub.