can1357/oh-my-pi · error · Error
Upload filename is invalid
Error message
Upload filename is invalid
What it means
Thrown by safeFileName when the derived upload filename contains a NUL byte or is exactly '.' or '..'. fileNameFor(request) computes the name from the upload request; the library refuses names that are path metacharacters or would corrupt remote filesystem entries.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts:107
return value.trim();
}
function pathParts(value: string | undefined): string[] {
if (!value) return [];
const parts = value.replaceAll("\\", "/").split("/");
const result: string[] = [];
for (const part of parts) {
if (!part || part === ".") continue;
if (part === ".." || part.includes("\0"))
throw new Error("Destination paths cannot contain parent traversal or NUL bytes");
result.push(part);
}
return result;
}
function safeFileName(request: BlobUploadRequest): string {
const name = fileNameFor(request);
if (name.includes("\0") || name === "." || name === "..") throw new Error("Upload filename is invalid");
return name;
}
function remotePath(directory: string | undefined, filename: string): string {
const absolute = directory?.replaceAll("\\", "/").startsWith("/") ?? false;
const joined = [...pathParts(directory), filename].join("/");
return absolute ? `/${joined}` : joined;
}
function encodedPath(parts: readonly string[]): string {
return parts.map(part => encodeURIComponent(part)).join("/");
}
function endpoint(base: string, ...parts: string[]): string {
const url = new URL(base);
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${encodedPath(parts)}`;
url.search = "";
url.hash = "";View on GitHub (pinned to 9690622007)
Solutions
- Sanitize the filename before the upload: strip NUL bytes and reject/basename '.' and '..' values
- Check what fileNameFor derives from in your request — supply an explicit valid filename instead of relying on derivation
- If iterating archive/zip entries, skip or rename entries whose names are '.' or '..' or contain '\0'
- Wrap the upload in a try-catch and surface a clearer user-facing 'invalid file name' message
Example fix
// before
await uploadBlob({ name: "..", content });
// after
const safe = rawName.replaceAll("\0", "") || "upload.bin";
await uploadBlob({ name: safe === "." || safe === ".." ? "upload.bin" : safe, content }); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeUploadName(raw: string): string {
const name = raw.replaceAll("\0", "");
if (!name || name === "." || name === "..") return "upload.bin";
return name;
}
await uploader.upload({ ...req, name: sanitizeUploadName(req.name) }); Type guard
function isValidUploadName(name: string): boolean {
return !name.includes("\0") && name !== "." && name !== "..";
} Try / catch
try {
await uploader.upload(blob);
} catch (err) {
if ((err as Error).message === "Upload filename is invalid") {
throw new Error(`Refusing upload: derived filename ${JSON.stringify(blob.name)} is '.', '..' or contains NUL`);
}
throw err;
} Prevention
- Sanitize filenames derived from URLs, archives, or user input before uploading
- Skip or rename '.'/'..'/NUL-containing entries when iterating archive contents
- Supply an explicit filename in the upload request instead of relying on path derivation
When it happens
Trigger: Uploading a blob whose request-derived filename is '.', '..', or contains '\0' — e.g. a request with an empty/weird source path that degenerates to '.', or programmatic callers passing a filename with an embedded NUL.
Common situations: Filename extracted from a URL/CFI/path that after normalization collapses to '.', uploading entries read from an archive with malicious names ('..' entries, NUL-padded names), or passing raw bytes-terminated C strings as filenames.
Related errors
- Provider delete URL must not embed an account credential
- Destination paths cannot contain parent traversal or NUL byt
- Shared-folder destination escapes its configured root
- Absolute paths are not allowed in ${scheme}:// URLs: ${rawPa
- Path traversal (..) is not allowed in ${scheme}:// URLs: ${r
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ccba98bf9102aa7c.
Report an issue: GitHub.