can1357/oh-my-pi · error · ArchiveError

Duplicate tar member path '${formatArchivePathForError(norma

Error message

Duplicate tar member path '${formatArchivePathForError(normalized)}'

What it means

The members map resolved to the same normalized path twice with incompatible intent (two files, a file and a directory, or a duplicate directory that isn't idempotent-mergeable). Tar archives cannot contain two members with the same name, so the encoder throws with the formatted path.

Source

Thrown at packages/utils/src/ar/tar.ts:764

		const pathBytes = TEXT_ENCODER.encode(normalized);
		if (pathBytes.byteLength === 0) throw new ArchiveError("Invalid empty tar member path");
		if (directory && bytes.byteLength !== 0) {
			throw new ArchiveError(`Tar directory '${formatArchivePathForError(normalized)}' cannot contain file data`);
		}
		const segments = normalized.split("/");
		for (let index = 1; index < segments.length; index++) {
			const parent = segments.slice(0, index).join("/");
			const kind = kinds.get(parent);
			if (kind === "file")
				throw new ArchiveError(`Tar member '${formatArchivePathForError(parent)}' is not a directory`);
			if (kind === "directory") continue;
			kinds.set(parent, "directory");
			appendTarEntry(parts, parent, new Uint8Array(0), true, sequence++);
		}
		const existing = kinds.get(normalized);
		if (existing) {
			if (directory && existing === "directory") continue;
			throw new ArchiveError(`Duplicate tar member path '${formatArchivePathForError(normalized)}'`);
		}
		kinds.set(normalized, directory ? "directory" : "file");
		appendTarEntry(parts, normalized, bytes, directory, sequence++);
	}
	parts.push(new Uint8Array(BLOCK_SIZE * 2));
	return concatBytes(parts);
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Normalize keys yourself and deduplicate the members map before createTar
  2. Merge duplicate entries by choosing or concatenating content upstream
  3. Use unique, already-normalized relative paths as keys

Example fix

// before
members.set("./x", a);
members.set("x", b); // normalizes to same path
// after
members.set("x", chooseContent(a, b));
Defensive patterns

Strategy: validation

Validate before calling

const seen = new Set<string>();
for (const key of members.keys()) {
	const norm = key.replace(/^\.\//, "").replace(/\/{2,}/g, "/");
	if (seen.has(norm)) throw new Error(`Duplicate member path after normalization: '${norm}'`);
	seen.add(norm);
}

Try / catch

try {
	return await createTar(members);
} catch (err) {
	if (err instanceof ArchiveError && err.message.startsWith("Duplicate tar member path")) {
		// merge or drop duplicates before retrying
	}
	throw err;
}

Prevention

When it happens

Trigger: Two distinct raw keys normalize to the same path (e.g. './x' and 'x', or 'a//b' and 'a/b'); a directory entry passed twice is tolerated, but any file duplication or dir/file clash throws.

Common situations: Case-insensitive or backslash-sourced listings collapsing to one key; merging archives; a zip importer yielding './' prefixed names.

Related errors


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