{"record":{"id":"1362927f258bd644","repo":"gastownhall/beads","slug":"no-proto-found-matching-q-by-id-or-title","errorCode":null,"errorMessage":"no proto found matching %q (by ID or title)","messagePattern":"no proto found matching %q \\(by ID or title\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/template.go","lineNumber":297,"sourceCode":"\n\tfor _, proto := range protos {\n\t\t// Check for exact title match (case-insensitive)\n\t\tif strings.EqualFold(proto.Title, input) {\n\t\t\texactMatch = proto\n\t\t\tbreak\n\t\t}\n\t\t// Check for partial title match (case-insensitive)\n\t\tif strings.Contains(strings.ToLower(proto.Title), strings.ToLower(input)) {\n\t\t\tmatches = append(matches, proto)\n\t\t}\n\t}\n\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)","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/template.go#L279-L315","documentation":"resolveProtoIDOrTitle exhausts both resolution strategies — exact ID lookup and title search — without a single matching proto. When the matches list is empty it throws 'no proto found matching %q (by ID or title)'. This is a user-input/resolution error: the requested template simply does not exist under that ID or title.","triggerScenarios":"Passing a title or partial ID to a proto-consuming command (spawn/bond/cook/burn flows that call resolveProtoIDOrTitle) where no issue labeled as a template matches either by ID or by title.","commonSituations":"Typo in molecule name; the proto lives in a different repo/.beads database; the proto was created without the template label so it is invisible to the search; casing/wording mismatch in the title.","solutions":["List existing protos to see available templates and copy the exact ID or title.","Verify the proto actually has the template label; re-add it if a manual edit stripped it.","Check you are in the repository that owns the proto (each repo has its own .beads database).","Create the proto first if it does not exist yet, then retry."],"exampleFix":"// before\nbd mol pour \"My Molecuel\"  // typo\n// after\nbd mol pour \"My Molecule\"  // exact title, or use the proto ID","handlingStrategy":"validation","validationCode":"// before invoking any proto command:\nprotos, _ := s.GetIssuesByLabel(ctx, BeadsTemplateLabel)\nfor _, p := range protos { fmt.Println(p.ID, p.Title) } // confirm exact match exists","typeGuard":null,"tryCatchPattern":"pid, err := resolveProtoIDOrTitle(ctx, s, input)\nif err != nil && strings.Contains(err.Error(), \"no proto found matching\") {\n\t// surface available protos to the user\n\treturn fmt.Errorf(\"%w; run protos list to see options\", err)\n}","preventionTips":["Copy proto IDs from a list command rather than typing titles.","Keep proto titles unique and descriptive.","Ensure protos carry the template label."],"tags":["template","not-found","resolution","cli"],"backgroundTag":"template-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}