{"record":{"id":"86607e9bdc4982bf","repo":"gastownhall/beads","slug":"cannot-resolve-issue-id-q-storage-is-nil","errorCode":null,"errorMessage":"cannot resolve issue ID %q: storage is nil","messagePattern":"cannot resolve issue ID %q: storage is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/id_parser.go","lineNumber":54,"sourceCode":"\t\treturn input\n\t}\n\n\treturn prefix + input\n}\n\n// ResolvePartialID resolves a potentially partial issue ID to a full ID.\n// Supports:\n// - Full IDs: \"bd-a3f8e9\" or \"a3f8e9\" → \"bd-a3f8e9\"\n// - Without hyphen: \"bda3f8e9\" or \"wya3f8e9\" → \"bd-a3f8e9\"\n// - Partial IDs: \"a3f8\" → \"bd-a3f8e9\" (if unique match)\n// - Hierarchical: \"a3f8e9.1\" → \"bd-a3f8e9.1\"\n//\n// Returns an error if:\n// - No issue found matching the ID\n// - Multiple issues match (ambiguous prefix)\nfunc ResolvePartialID(ctx context.Context, store PartialIDResolverStore, input string) (string, error) {\n\tif store == nil {\n\t\treturn \"\", fmt.Errorf(\"cannot resolve issue ID %q: storage is nil\", input)\n\t}\n\n\t// Fast path: Use SearchIssues with exact ID filter (GH#942).\n\t// This uses the same query path as \"bd list --id\", ensuring consistency.\n\t// Previously we used GetIssue which could fail in cases where SearchIssues\n\t// with filter.IDs succeeded, likely due to subtle query differences.\n\texactFilter := types.IssueFilter{IDs: []string{input}}\n\tif issues, err := store.SearchIssues(ctx, \"\", exactFilter); err == nil && len(issues) > 0 {\n\t\treturn issues[0].ID, nil\n\t}\n\n\t// Get the configured prefix\n\tprefix, err := store.GetConfig(ctx, \"issue_prefix\")\n\tif err != nil || prefix == \"\" {\n\t\tprefix = \"bd\"\n\t}\n\n\t// Ensure prefix has hyphen for ID format","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/utils/id_parser.go#L36-L72","documentation":"ResolvePartialID resolves a partial or prefixed issue ID against storage. It immediately rejects a nil PartialIDResolverStore with this error, because no lookup is possible without a backing store.","triggerScenarios":"Calling ResolvePartialID(ctx, nil, input) — directly or via ResolvePartialID(s) — before a store/database handle has been opened or assigned.","commonSituations":"Calling ID resolution during CLI startup before the Dolt/SQLite store is initialized; dependency-injection wiring that left the store field nil; tests constructing the resolver without a store.","solutions":["Initialize/open the storage backend and pass the resulting store to ResolvePartialID","Fix DI wiring so the PartialIDResolverStore is set before any ID resolution runs","Guard call sites: skip resolution when the store is nil, or return a clearer init error"],"exampleFix":"// before\nid, err := utils.ResolvePartialID(ctx, nil, \"a3f8\") // storage is nil\n// after\nstore, err := storage.Open(ctx, dbPath)\nif err != nil { return err }\nid, err := utils.ResolvePartialID(ctx, store, \"a3f8\")","handlingStrategy":"type-guard","validationCode":"func resolveSafely(ctx context.Context, store utils.PartialIDResolverStore, input string) (string, error) {\n\tif store == nil {\n\t\treturn \"\", fmt.Errorf(\"storage not initialized: open the database before resolving IDs\")\n\t}\n\treturn utils.ResolvePartialID(ctx, store, input)\n}","typeGuard":"func storeReady(store utils.PartialIDResolverStore) bool { return store != nil }","tryCatchPattern":"id, err := utils.ResolvePartialID(ctx, store, input)\nif err != nil {\n\tif strings.Contains(err.Error(), \"storage is nil\") {\n\t\treturn fmt.Errorf(\"run 'bd init' or open the database first: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Open the store before any ID resolution in the startup path","Make store fields non-nil by construction (fail fast at init)","In tests, always inject a stub PartialIDResolverStore"],"tags":["go","nil-store","id-resolution","initialization"],"backgroundTag":"nil-storage-handle","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}