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

  1. Sanitize the filename before the upload: strip NUL bytes and reject/basename '.' and '..' values
  2. Check what fileNameFor derives from in your request — supply an explicit valid filename instead of relying on derivation
  3. If iterating archive/zip entries, skip or rename entries whose names are '.' or '..' or contain '\0'
  4. 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

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


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