can1357/oh-my-pi · error · ArchiveError
Invalid tar member path '${formatArchivePathForError(rawPath
Error message
Invalid tar member path '${formatArchivePathForError(rawPath)}' What it means
normalizeArchiveEntryPath sanitizes a tar member path (resolving ., .., drive/backslash forms); when it returns empty the raw path was invalid (e.g. only traversal segments, null bytes, or nothing usable). The library throws rather than writing a header for an unusable path, and includes the formatted raw path in the message.
Source
Thrown at packages/utils/src/ar/tar.ts:745
effectiveSplit[1],
size <= MAX_OCTAL_SIZE ? size : 0,
mtime,
directory ? 0o755 : 0o644,
directory ? 0x35 : 0x30,
),
);
if (!directory) appendPayload(parts, payload);
}
/** Encode files as a deterministic ustar archive, using PAX records for overflow paths. */
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;View on GitHub (pinned to 9690622007)
Solutions
- Sanitize or re-key members to clean relative paths like 'dir/file.txt' before calling createTar
- Strip leading slashes and resolve '..' segments yourself
- Skip empty, '.', '..', and null-containing keys
Example fix
// before const members = new Map([["../escape.txt", data]]); await createTar(members); // after const members = new Map([["safe/escape.txt", data]]); await createTar(members);
Defensive patterns
Strategy: validation
Validate before calling
function isSafeMemberPath(p: string): boolean {
if (p.length === 0 || p.includes("\0")) return false;
const parts = p.replace(/\\/g, "/").split("/");
return !parts.some((s) => s === ".." || s === "." || s === "");
} Type guard
function isSafeMemberPath(p: string): boolean {
if (p.length === 0 || p.includes("\0")) return false;
const parts = p.replace(/\\/g, "/").split("/");
return !parts.some((s) => s === ".." || s === "." || s === "");
} Try / catch
try {
return await createTar(members);
} catch (err) {
if (err instanceof ArchiveError && err.message.startsWith("Invalid tar member path")) {
// log rejected path from err.message and sanitize keys
}
throw err;
} Prevention
- Sanitize entry names from untrusted sources (strips '..', absolute prefixes, NULs)
- Never key members with '.', '..', or empty strings
- Normalize backslash paths to forward slashes yourself
When it happens
Trigger: createTar called with a key like '../etc/passwd', '.', '..', an empty string, a path containing NUL, or a backslash-only/Windows-style path that normalizes to nothing.
Common situations: Building archives from untrusted ZIP-style entry names; copying an in-memory virtual FS where root or '.' was included as a member; joining paths so a key became '..'.
Related errors
- Invalid old-GNU ${field}
- Invalid empty tar member path
- Tar directory '${formatArchivePathForError(normalized)}' can
- Archive write path must target a file inside the archive
- Archive write path must target a file, not a directory
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e6d276fbdb60b4ff.
Report an issue: GitHub.