{"record":{"id":"21a631121afa5525","repo":"block/buzz","slug":"the-mention-winners-0-displayname-is-ambiguou","errorCode":null,"errorMessage":"The mention @${winners[0].displayName} is ambiguous. Choose a recipient from the mention picker.","messagePattern":"The mention @(.+?) is ambiguous\\. Choose a recipient from the mention picker\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"desktop/src/features/messages/lib/extractMentionPubkeys.ts","lineNumber":135,"sourceCode":"/** Extract recipients from the same exact occurrences used by draft routing. */\nexport function extractMentionPubkeys(options: {\n  text: string;\n  selectedMentions: ReadonlyMap<string, string>;\n  selectedDisplayNames?: Iterable<string>;\n  competingDisplayNames?: Iterable<string>;\n  memberCandidates: readonly MentionPubkeyCandidate[];\n}): string[] {\n  const { text, selectedMentions, memberCandidates } = options;\n  const candidates = mentionMatchCandidates(options);\n  const winningPubkeys = new Set<string>();\n  for (const { candidates: winners } of mentionOccurrences(text, candidates)) {\n    const identities = new Set(\n      winners.flatMap((match) =>\n        match.pubkey ? [match.pubkey.toLowerCase()] : [],\n      ),\n    );\n    if (identities.size > 1) {\n      throw new Error(\n        `The mention @${winners[0].displayName} is ambiguous. Choose a recipient from the mention picker.`,\n      );\n    }\n    for (const match of winners) {\n      if (match.pubkey) winningPubkeys.add(match.pubkey);\n    }\n  }\n\n  const pubkeys: string[] = [];\n  for (const [, pubkey] of selectedMentions) {\n    if (winningPubkeys.delete(pubkey)) pubkeys.push(pubkey);\n  }\n  for (const candidate of memberCandidates) {\n    if (candidate.pubkey && winningPubkeys.delete(candidate.pubkey)) {\n      pubkeys.push(candidate.pubkey);\n    }\n  }\n  return pubkeys;","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/desktop/src/features/messages/lib/extractMentionPubkeys.ts#L117-L153","documentation":"extractMentionPubkeys resolves typed @Name mentions to pubkeys. When the winning display-name matches multiple distinct identities (identities.size > 1), the mention is ambiguous — the code throws rather than silently fanning out to all same-named identities, per the mention editor contract.","triggerScenarios":"A message body contains @Name where two or more registered identities (teammates, agents, automatic addresses) share that exact displayName, and the text was typed manually rather than picked from the mention picker.","commonSituations":"Two teammates with the same display name joined the community; a user and an agent share a name; a message was pasted or edited so the mention text no longer carries its original pubkey binding.","solutions":["Re-enter the mention via the mention picker (autocomplete) so the exact pubkey is bound and no ambiguity check runs.","Rename one of the colliding identities (or use its distinguishing handle) so typed names resolve uniquely.","Remove or rewrite the ambiguous mention text in the draft.","If the collision is stale, refresh the directory so duplicates that no longer exist disappear."],"exampleFix":"// before\nconst pubkeys = extractMentionPubkeys(content); // throws on '@Sam' with two Sams\n\n// after\ntry {\n  const pubkeys = extractMentionPubkeys(content);\n} catch (e) {\n  if (String(e?.message).includes(\"is ambiguous\")) {\n    openMentionPicker(); // force explicit recipient selection\n    return null;\n  }\n  throw e;\n}","handlingStrategy":"validation","validationCode":"const matches = directory.lookupByName(name);\nif (new Set(matches.map(m => m.pubkey?.toLowerCase()).filter(Boolean)).size > 1) {\n  openMentionPicker(name); // force explicit disambiguation\n}","typeGuard":"function isUnambiguousName(name: string, dir: Directory): boolean {\n  const ids = new Set(\n    dir.lookupByName(name).flatMap(m => (m.pubkey ? [m.pubkey.toLowerCase()] : [])),\n  );\n  return ids.size <= 1;\n}","tryCatchPattern":"try {\n  const { pubkeys } = extractMentionPubkeys(body);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"is ambiguous\")) {\n    highlightAmbiguousMentionInDraft();\n    return;\n  }\n  throw e;\n}","preventionTips":["Prefer picker-inserted mentions (pubkey-bound) over free-typed names.","Disambiguate duplicate display names in the community (renames or handles).","Highlight ambiguous text in drafts before submit.","Test mention extraction with same-named teammates and name-sharing agents."],"tags":["mentions","ambiguity","validation","messages"],"backgroundTag":"ambiguous-mention-name","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-09-05T18:13:50.666Z","contentChangedAt":"2026-09-05T18:13:50.666Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}