{"record":{"id":"63c8a63419e0f747","repo":"gastownhall/beads","slug":"ambiguous-q-matches-d-protos-s-use-the-id-o","errorCode":null,"errorMessage":"ambiguous: %q matches %d protos:\n  %s\nUse the ID or a more specific title","messagePattern":"ambiguous: %q matches (.+?) protos:\n  (.+?)\nUse the ID or a more specific title","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/template.go","lineNumber":309,"sourceCode":"\n\tif exactMatch != nil {\n\t\treturn exactMatch.ID, nil\n\t}\n\n\tif len(matches) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no proto found matching %q (by ID or title)\", input)\n\t}\n\n\tif len(matches) == 1 {\n\t\treturn matches[0].ID, nil\n\t}\n\n\t// Multiple matches - show them all for disambiguation\n\tvar matchNames []string\n\tfor _, m := range matches {\n\t\tmatchNames = append(matchNames, fmt.Sprintf(\"%s: %s\", m.ID, m.Title))\n\t}\n\treturn \"\", fmt.Errorf(\"ambiguous: %q matches %d protos:\\n  %s\\nUse the ID or a more specific title\", input, len(matches), strings.Join(matchNames, \"\\n  \"))\n}\n\n// extractVariables finds all {{variable}} patterns in text.\n// Handlebars control keywords like \"else\", \"this\" are excluded.\nfunc extractVariables(text string) []string {\n\tmatches := variablePattern.FindAllStringSubmatch(text, -1)\n\tseen := make(map[string]bool)\n\tvar vars []string\n\tfor _, match := range matches {\n\t\tif len(match) >= 2 && !seen[match[1]] {\n\t\t\tname := match[1]\n\t\t\t// Skip Handlebars control keywords\n\t\t\tif isHandlebarsKeyword(name) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvars = append(vars, name)\n\t\t\tseen[name] = true\n\t\t}","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/template.go#L291-L327","documentation":"When resolveProtoIDOrTitle's title search matches multiple protos, it cannot choose for the user. It formats every match as 'ID: Title' and throws the 'ambiguous: ... matches %d protos' error, instructing the caller to use the exact ID or a more specific title. This is an intentional disambiguation guard, not a malfunction.","triggerScenarios":"Invoking a proto command with a title string that is a substring/prefix of, or otherwise matches, several template-labeled issues — e.g. two protos titled 'Deploy' and 'Deploy Service'.","commonSituations":"Generic proto names like 'test' or 'build' colliding across teams; duplicated protos created before a rename; case differences that the fuzzy matcher treats as matches.","solutions":["Re-run the command with the proto's exact ID instead of its title.","Use a longer, more specific title substring that matches only one proto.","Rename duplicate protos to distinct titles to prevent future ambiguity.","Delete or consolidate stale duplicate protos."],"exampleFix":"// before\nbd mol pour deploy            // ambiguous: matches 3 protos\n// after\nbd mol pour bd-abc123          // use the exact ID","handlingStrategy":"fallback","validationCode":"// disambiguate up front:\nmatches := filterByName(protos, input)\nif len(matches) > 1 { fmt.Println(\"use exact ID:\"); for _, m := range matches { fmt.Println(m.ID, m.Title) } }","typeGuard":null,"tryCatchPattern":"pid, err := resolveProtoIDOrTitle(ctx, s, input)\nif err != nil && strings.Contains(err.Error(), \"ambiguous:\") {\n\t// parse listed matches from err and prompt user to choose an ID\n\treturn err\n}","preventionTips":["Prefer exact IDs in scripts and CI.","Rename protos so titles are unique.","Avoid overly generic proto names."],"tags":["template","ambiguity","resolution","cli"],"backgroundTag":"ambiguous-template-match","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}