{"record":{"id":"2248503a3dd7461e","repo":"gastownhall/beads","slug":"errambiguousid","errorCode":"ErrAmbiguousID","errorMessage":"ambiguous issue ID","messagePattern":"ambiguous issue ID","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/id_parser.go","lineNumber":18,"sourceCode":"// Package utils provides utility functions for issue ID parsing and resolution.\npackage utils\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/steveyegge/beads/internal/types\"\n)\n\n// ErrAmbiguousID is the sentinel wrapped into the error ResolvePartialID\n// returns when a partial ID matches more than one issue. Callers use\n// errors.Is(err, ErrAmbiguousID) to distinguish \"ambiguous\" from\n// \"not found\" and surface the candidate list instead of a generic failure.\nvar ErrAmbiguousID = errors.New(\"ambiguous issue ID\")\n\ntype PartialIDResolverStore interface {\n\tSearchIssues(ctx context.Context, query string, filter types.IssueFilter) ([]*types.Issue, error)\n\tSearchIssueIDs(ctx context.Context, query string, filter types.IssueFilter) ([]string, error)\n\tGetConfig(ctx context.Context, key string) (string, error)\n}\n\n// parseIssueID ensures an issue ID has the configured prefix.\n// If the input already has the prefix (e.g., \"bd-a3f8e9\"), returns it as-is.\n// If the input lacks the prefix (e.g., \"a3f8e9\"), adds the configured prefix.\n// Works with hierarchical IDs too: \"a3f8e9.1.2\" → \"bd-a3f8e9.1.2\"\nfunc parseIssueID(input string, prefix string) string {\n\tif prefix == \"\" {\n\t\tprefix = \"bd-\"\n\t}\n\n\tif strings.HasPrefix(input, prefix) {\n\t\treturn input","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/utils/id_parser.go#L1-L36","documentation":"ErrAmbiguousID is the sentinel wrapped into the error ResolvePartialID returns when a partial (abbreviated) issue ID matches more than one issue. It lets callers distinguish 'ambiguous' from 'not found' via errors.Is and surface the candidate list instead of a generic failure. Declared in internal/utils/id_parser.go.","triggerScenarios":"Calling ResolvePartialID with a short ID prefix that matches multiple issues, e.g. 'bd-1' matching bd-10, bd-12, bd-123; using an abbreviated ID in commands like bd show, bd close, or bd update where the prefix is not unique.","commonSituations":"Large backlogs where short numeric prefixes collide; copy-pasting a truncated ID from a teammate; typing 'bd show 12' when bd-12 and bd-123 both exist.","solutions":["Use the full, unique issue ID (e.g. bd-123) instead of the partial prefix.","Lengthen the prefix until it matches exactly one issue.","Inspect the candidate list in the wrapped error and pick the intended issue.","List matching issues (bd list with the prefix as a query) to disambiguate."],"exampleFix":"// before\nid, err := utils.ResolvePartialID(ctx, store, \"bd-1\") // ambiguous\n\n// after\nid, err := utils.ResolvePartialID(ctx, store, \"bd-123\")\nif errors.Is(err, utils.ErrAmbiguousID) {\n    // surface err's candidate list to the user\n}","handlingStrategy":"try-catch","validationCode":"ids, _ := store.SearchIssueIDs(ctx, partial, types.IssueFilter{})\nif len(ids) != 1 {\n    // disambiguate before resolving\n}","typeGuard":null,"tryCatchPattern":"id, err := utils.ResolvePartialID(ctx, store, partial)\nif errors.Is(err, utils.ErrAmbiguousID) {\n    // show candidate list from wrapped error\n}","preventionTips":["Use full IDs in scripts and automation.","Extend prefixes until unique before passing to commands.","Surface candidate lists to interactive users instead of guessing."],"tags":["id-resolution","ambiguity","cli"],"backgroundTag":"ambiguous-identifier","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}