can1357/oh-my-pi · error · ArchiveError
Tar member '${formatArchivePathForError(parent)}' is not a d
Error message
Tar member '${formatArchivePathForError(parent)}' is not a directory What it means
While inserting implicit parent directory entries, the encoder found a parent path already registered as a regular file. A tar path cannot be both a file and a prefix of another member, so it throws naming the offending parent.
Source
Thrown at packages/utils/src/ar/tar.ts:756
export async function encodeTar(members: Iterable<readonly [string, Uint8Array]>): Promise<Uint8Array> {
const parts: Uint8Array[] = [];
const kinds = new Map<string, "directory" | "file">();
let sequence = 0;
for (const [rawPath, bytes] of members) {
const directory = rawPath.endsWith("/") || rawPath.endsWith("\\");
const normalized = normalizeArchiveEntryPath(rawPath);
if (!normalized) throw new ArchiveError(`Invalid tar member path '${formatArchivePathForError(rawPath)}'`);
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
- Rename one of the conflicting members so no path is both a file and a directory prefix
- Drop the file entry 'a' or nest its data at another key
- Deduplicate/validate the members map keys before encoding
Example fix
// before
members.set("a", fileBytes);
members.set("a/b", otherBytes); // conflict
// after
members.set("a-collision", fileBytes);
members.set("a/b", otherBytes); Defensive patterns
Strategy: validation
Validate before calling
const fileKeys = new Set(
[...members.entries()].filter(([, b]) => b.byteLength > 0 && !/[\\/]$/.test(k0(b)))
);
function k0(x: unknown) { return x as string; }
for (const key of members.keys()) {
const segs = key.split("/");
for (let i = 1; i < segs.length; i++) {
const parent = segs.slice(0, i).join("/");
if (fileKeys.has(parent)) throw new Error(`'${parent}' is a file but '${key}' needs it as a directory`);
}
} Try / catch
try {
return await createTar(members);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("is not a directory")) {
// rename one of the colliding members
}
throw err;
} Prevention
- Before encoding, verify no member path is a prefix of another member while being a file
- Deduplicate keys after path normalization
- Validate merged member sets from multiple sources
When it happens
Trigger: Members include both 'a' (a file with bytes) and 'a/b' (a file) — the encoder must synthesize directory 'a' for 'a/b' but 'a' is already a file.
Common situations: Merging member sets from multiple sources; keys derived from filesystem scans where 'a' is a file but a stale key 'a/b' persisted; path collisions after normalization (e.g. 'a' vs './a').
Related errors
- Duplicate tar member path '${formatArchivePathForError(norma
- Invalid tar octal value: ${value}
- Truncated embedded addon archive entry: ${filename}
- Unsafe embedded addon archive entry: ${filename}
- Unsupported embedded addon archive entry type ${typeflag}: $
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/85074286bd3906a9.
Report an issue: GitHub.