schollz/croc · error · Error

Remote filename is empty

Error message

Remote filename is empty

What it means

normalizeFilePath() throws when the single name segment is empty — i.e. the filename normalizes to nothing (empty string, '.', or a bare '/'). A file with no name cannot be saved, so the offer is rejected before any destination path is built.

Source

Thrown at web/src/protocol/metadata.ts:43

  if (/^(?:[a-zA-Z]:|\/)/.test(value)) {
    throw new Error(`Remote path must be relative: ${value}`);
  }
  const segments = cleanSegments(value);
  const normalized = segments.join("/") || ".";
  if (normalized.includes(".ssh")) {
    throw new Error(`Remote path is not allowed: ${value}`);
  }
  return normalized;
}

export function normalizeFilePath(folderValue: string, nameValue: string) {
  const folder = normalizeFolder(folderValue);
  const nameSegments = cleanSegments(nameValue);
  if (nameSegments.length !== 1 || nameSegments[0] !== nameValue.replaceAll("\\", "/")) {
    throw new Error(`Remote filename must be a basename: ${nameValue}`);
  }
  const name = nameSegments[0];
  if (!name) throw new Error("Remote filename is empty");
  const path = folder === "." ? name : `${folder}/${name}`;
  return { folder, name, path };
}

export function normalizeOutgoingFileName(value: string) {
  // Go's unicode.IsPrint accepts ASCII space but rejects the other Unicode
  // separator characters commonly inserted into filenames by macOS.
  const compatible = value.replace(/\p{Z}+/gu, " ");
  return normalizeFilePath(".", compatible).name;
}

function finiteSize(file: WireFileInfo) {
  const size = file.s ?? 0;
  if (!Number.isSafeInteger(size) || size < 0) {
    throw new Error(`Invalid file size for ${file.n ?? "unnamed file"}`);
  }
  return size;
}

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Ensure every file entry in the offer has a real basename in the 'n' field.
  2. On the sender, derive names with path splitting that cannot return '' (guard against trailing slashes).
  3. As a receiver, refuse offers that fail here — there is no sensible default filename to substitute safely.
Defensive patterns

Strategy: validation

Validate before calling

function hasNonEmptyBasename(value: string): boolean {
  const replaced = value.replaceAll("\\", "/").replace(/\/+$/, "");
  return replaced !== "" && replaced !== ".";
}

Try / catch

try {
  const { name } = normalizeFilePath(folder, candidateName);
} catch (error) {
  if (error instanceof Error && error.message === "Remote filename is empty") {
    rejectOffer("file entry has no name");
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: normalizeFilePath(folder, '') — typically an offered file whose wire 'n' field is missing (wire.n ?? '' fallback in validateSenderInfo) or is '.' or '/'. Also reachable via normalizeOutgoingFileName('') or ('.').

Common situations: Hostile/buggy peer omitting the name field; sender code building offers with an empty filename (e.g. path.basename returning '' for directory-like inputs); a directory entry mistakenly listed in FilesToTransfer.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/96b82bcd3e081564. Report an issue: GitHub.