{"record":{"id":"3478377767fd5bd0","repo":"schollz/croc","slug":"duplicate-destination-path-folder","errorCode":null,"errorMessage":"Duplicate destination path: ${folder}","messagePattern":"Duplicate destination path: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/metadata.ts","lineNumber":95,"sourceCode":"    }\n    destinations.add(normalized.path);\n    const size = finiteSize(wire);\n    totalSize += size;\n    if (!Number.isSafeInteger(totalSize)) throw new Error(\"Transfer size is too large\");\n    files.push({\n      ...normalized,\n      size,\n      hash: wire.h ? base64ToBytes(wire.h) : new Uint8Array(),\n      modified: wire.m,\n      mode: wire.md,\n    });\n  }\n\n  const emptyFolders: string[] = [];\n  for (const wire of info.EmptyFoldersToTransfer ?? []) {\n    const folder = normalizeFolder(wire.fr ?? \".\");\n    if (destinations.has(folder)) {\n      throw new Error(`Duplicate destination path: ${folder}`);\n    }\n    destinations.add(folder);\n    emptyFolders.push(folder);\n  }\n\n  return {\n    files,\n    emptyFolders,\n    totalSize,\n    senderMachineID: info.MachineID || \"unknown\",\n    noCompress: Boolean(info.NoCompress),\n  };\n}\n","sourceCodeStart":77,"sourceCodeEnd":109,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/metadata.ts#L77-L109","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Fix the sender so empty-folder paths never equal any file destination path and folders are listed once.","On the receiver, refuse such offers outright — the collision is ambiguous metadata.","In tests, keep file destinations and EmptyFoldersToTransfer entries disjoint."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function folderPathsAreDisjoint(info: SenderInfoWire): boolean {\n  const fileDests = new Set((info.FilesToTransfer ?? []).map((f) => `${f.fr ?? \".\"}/${f.n ?? \"\"}`));\n  const folders = (info.EmptyFoldersToTransfer ?? []).map((f) => f.fr ?? \".\");\n  return new Set(folders).size === folders.length && folders.every((d) => !fileDests.has(d));\n}","typeGuard":null,"tryCatchPattern":"try {\n  const offer = validateSenderInfo(info);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"Duplicate destination path\")) {\n    rejectOffer(\"folder/file destination collision\");\n    return;\n  }\n  throw error;\n}","preventionTips":["Keep empty-folder entries unique and disjoint from file destinations when building offers.","Generate offers from a directory walk that cannot emit both a file and a folder at one path.","Reject colliding offers on the receiver; do not guess precedence."],"tags":["validation","metadata","deduplication"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}