schollz/croc · error · Error

Duplicate destination path: ${folder}

Error message

Duplicate destination path: ${folder}

What it means

While ingesting EmptyFoldersToTransfer, validateSenderInfo() reuses the same destinations Set used for files and throws if an empty folder's normalized path collides with an already-registered destination. A folder path identical to a file path (or a repeated folder) is contradictory metadata that would confuse the sink, so it is rejected.

Source

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

    }
    destinations.add(normalized.path);
    const size = finiteSize(wire);
    totalSize += size;
    if (!Number.isSafeInteger(totalSize)) throw new Error("Transfer size is too large");
    files.push({
      ...normalized,
      size,
      hash: wire.h ? base64ToBytes(wire.h) : new Uint8Array(),
      modified: wire.m,
      mode: wire.md,
    });
  }

  const emptyFolders: string[] = [];
  for (const wire of info.EmptyFoldersToTransfer ?? []) {
    const folder = normalizeFolder(wire.fr ?? ".");
    if (destinations.has(folder)) {
      throw new Error(`Duplicate destination path: ${folder}`);
    }
    destinations.add(folder);
    emptyFolders.push(folder);
  }

  return {
    files,
    emptyFolders,
    totalSize,
    senderMachineID: info.MachineID || "unknown",
    noCompress: Boolean(info.NoCompress),
  };
}

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Fix the sender so empty-folder paths never equal any file destination path and folders are listed once.
  2. On the receiver, refuse such offers outright — the collision is ambiguous metadata.
  3. In tests, keep file destinations and EmptyFoldersToTransfer entries disjoint.
Defensive patterns

Strategy: validation

Validate before calling

function folderPathsAreDisjoint(info: SenderInfoWire): boolean {
  const fileDests = new Set((info.FilesToTransfer ?? []).map((f) => `${f.fr ?? "."}/${f.n ?? ""}`));
  const folders = (info.EmptyFoldersToTransfer ?? []).map((f) => f.fr ?? ".");
  return new Set(folders).size === folders.length && folders.every((d) => !fileDests.has(d));
}

Try / catch

try {
  const offer = validateSenderInfo(info);
} catch (error) {
  if (error instanceof Error && error.message.startsWith("Duplicate destination path")) {
    rejectOffer("folder/file destination collision");
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: An offer where an empty folder's fr normalizes to the same string as a file's destination path — e.g. file at 'a/b/c.txt' plus empty folder 'a/b/c.txt' — or the same empty folder listed twice (second occurrence hits the Set).

Common situations: Hostile peer mixing file and folder destinations to test precedence; sender bug that lists a directory both as an (empty) folder and with a phantom file; test fixtures with overlapping entries.

Related errors


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