{"record":{"id":"8dee75ce704660ba","repo":"sipeed/picoclaw","slug":"mcp-server-names-must-be-unique-duplicates-dup","errorCode":null,"errorMessage":"MCP server names must be unique. Duplicates: ${duplicateNames.join(\", \")}.","messagePattern":"MCP server names must be unique\\. Duplicates: (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"web/frontend/src/components/config/config-page.tsx","lineNumber":439,"sourceCode":"              envFile: server.envFile.trim(),\n            }))\n            .filter((server) => server.name !== \"\")\n\n          const serverNameCounts = new Map<string, number>()\n          for (const server of normalizedServers) {\n            serverNameCounts.set(\n              server.name,\n              (serverNameCounts.get(server.name) ?? 0) + 1,\n            )\n          }\n\n          const duplicateNames = Array.from(serverNameCounts.entries())\n            .filter(([, count]) => count > 1)\n            .map(([name]) => name)\n            .sort((a, b) => a.localeCompare(b))\n\n          if (duplicateNames.length > 0) {\n            throw new Error(\n              `MCP server names must be unique. Duplicates: ${duplicateNames.join(\", \")}.`,\n            )\n          }\n\n          const currentServerNames = new Set(\n            normalizedServers.map((server) => server.name),\n          )\n\n          const removedServerEntries = Array.from(baselineServerNames)\n            .filter((name) => !currentServerNames.has(name))\n            .map((name) => [name, null] as const)\n\n          const baselineServersByName = new Map(\n            baseline.mcpServers\n              .map((server) => ({\n                ...server,\n                name: server.name.trim(),\n              }))","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/web/frontend/src/components/config/config-page.tsx#L421-L457","documentation":"Validation error thrown in handleSave (web/frontend/src/components/config/config-page.tsx:439) when two or more MCP server entries share the same trimmed name. Server names are the keys of the mcpServers patch object, so duplicates would silently overwrite each other; the code builds a name-count map, sorts the duplicate names, and lists them in the message before aborting the save.","triggerScenarios":"Adding a second server row and typing a name identical (after trimming) to an existing one; a saved config already containing duplicate names that surfaces on the next edit; names differing only by surrounding spaces normalize to the same trimmed value.","commonSituations":"User clones a server row to tweak a URL and forgets to rename; two people merge config edits introducing the same name 'github'; whitespace differences make names look distinct in the UI.","solutions":["Rename each duplicate listed in the message so every server name is unique","Delete the accidental clone row if it was a copy-paste leftover","Check for invisible leading/trailing spaces — names are trimmed before comparison"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function findDuplicateServerNames(servers: { name: string }[]): string[] {\n  const counts = new Map<string, number>()\n  for (const s of servers) {\n    const n = s.name.trim()\n    if (n === \"\") continue\n    counts.set(n, (counts.get(n) ?? 0) + 1)\n  }\n  return [...counts.entries()].filter(([, c]) => c > 1).map(([n]) => n)\n}\n\n// call before building the patch\nconst dups = findDuplicateServerNames(form.mcpServers)\nif (dups.length > 0) {\n  setFieldError(`MCP server names must be unique. Duplicates: ${dups.join(\", \")}.`)\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleSave()\n} catch (err) {\n  if (err instanceof Error) setError(err.message) // message lists the duplicate names\n}","preventionTips":["Flag duplicate names inline as the user types, per row","After cloning a server row, auto-suffix the name (e.g. 'github (2)') and force a rename before enable","Trim names on blur so whitespace-only differences cannot hide duplicates"],"tags":["validation","frontend","mcp","config","uniqueness"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}