can1357/oh-my-pi · error · ToolError
Archive write path must target a file inside the archive
Error message
Archive write path must target a file inside the archive
What it means
When writing into an archive (zip/sqlite-style targets), the sub-path after the archive prefix must name an entry inside it. An empty sub-path gives the tool nothing to write, so it fails closed.
Source
Thrown at packages/coding-agent/src/tools/write.ts:462
}
interface ResolvedSqliteWritePath {
absolutePath: string;
sqlitePath: string;
table: string;
key?: string;
exists: boolean;
}
function isArchivePathNotFound(error: unknown): boolean {
if (isEnoent(error)) return true;
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOTDIR";
}
function normalizeArchiveWriteSubPath(rawPath: string): string {
const normalized = rawPath.replace(/\\/g, "/");
if (normalized.length === 0) {
throw new ToolError("Archive write path must target a file inside the archive");
}
if (normalized.endsWith("/")) {
throw new ToolError("Archive write path must target a file, not a directory");
}
const parts = normalized.split("/");
const normalizedParts: string[] = [];
for (const part of parts) {
if (!part || part === ".") continue;
if (part === "..") {
throw new ToolError("Archive path cannot contain '..'");
}
normalizedParts.push(part);
}
if (normalizedParts.length === 0) {
throw new ToolError("Archive write path must target a file inside the archive");
}View on GitHub (pinned to 9690622007)
Solutions
- Append the entry path: write({ path: "archive.zip/dir/file.txt", content })
- Remove the trailing slash and supply a concrete file name inside the archive
Example fix
// before
write({ path: "bundle.zip/", content: "x" })
// after
write({ path: "bundle.zip/assets/file.txt", content: "x" }) Defensive patterns
Strategy: validation
Validate before calling
function validateArchiveTarget(p: string): string | null {
const sub = p.replace(/^[^/]+\//, "").replace(/\\/g, "/");
if (sub.trim().length === 0 || sub === "") return "empty archive sub-path";
return null;
} Try / catch
try {
await write({ path: target, content });
} catch (e) {
if (e instanceof ToolError && /must target a file inside the archive/.test(e.message)) {
throw new Error(`Supply an in-archive entry path, got: ${target}`);
}
throw e;
} Prevention
- Always append a concrete entry file name after the archive prefix
- Check for template/variable substitution leaving the sub-path empty
- Strip trailing slashes from constructed archive targets
When it happens
Trigger: write({ path: "archive.zip/" }) or a target whose in-archive sub-path normalizes to empty (e.g. only slashes or dots after the archive root).
Common situations: Trailing-slash typos, forgetting the entry name after the archive path, template substitution leaving the sub-path blank.
Related errors
- Archive write path must target a file, not a directory
- Invalid old-GNU ${field}
- Invalid tar member path '${formatArchivePathForError(rawPath
- Invalid empty tar member path
- Tar directory '${formatArchivePathForError(normalized)}' can
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/14513e5da5a5940b.
Report an issue: GitHub.