gastownhall/beads · error
cannot resolve issue ID %q: storage is nil
Error message
cannot resolve issue ID %q: storage is nil
What it means
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.
Source
Thrown at internal/utils/id_parser.go:54
return input
}
return prefix + input
}
// ResolvePartialID resolves a potentially partial issue ID to a full ID.
// Supports:
// - Full IDs: "bd-a3f8e9" or "a3f8e9" → "bd-a3f8e9"
// - Without hyphen: "bda3f8e9" or "wya3f8e9" → "bd-a3f8e9"
// - Partial IDs: "a3f8" → "bd-a3f8e9" (if unique match)
// - Hierarchical: "a3f8e9.1" → "bd-a3f8e9.1"
//
// Returns an error if:
// - No issue found matching the ID
// - Multiple issues match (ambiguous prefix)
func ResolvePartialID(ctx context.Context, store PartialIDResolverStore, input string) (string, error) {
if store == nil {
return "", fmt.Errorf("cannot resolve issue ID %q: storage is nil", input)
}
// Fast path: Use SearchIssues with exact ID filter (GH#942).
// This uses the same query path as "bd list --id", ensuring consistency.
// Previously we used GetIssue which could fail in cases where SearchIssues
// with filter.IDs succeeded, likely due to subtle query differences.
exactFilter := types.IssueFilter{IDs: []string{input}}
if issues, err := store.SearchIssues(ctx, "", exactFilter); err == nil && len(issues) > 0 {
return issues[0].ID, nil
}
// Get the configured prefix
prefix, err := store.GetConfig(ctx, "issue_prefix")
if err != nil || prefix == "" {
prefix = "bd"
}
// Ensure prefix has hyphen for ID formatView on GitHub (pinned to 71377f2769)
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
Example fix
// before
id, err := utils.ResolvePartialID(ctx, nil, "a3f8") // storage is nil
// after
store, err := storage.Open(ctx, dbPath)
if err != nil { return err }
id, err := utils.ResolvePartialID(ctx, store, "a3f8") Defensive patterns
Strategy: type-guard
Validate before calling
func resolveSafely(ctx context.Context, store utils.PartialIDResolverStore, input string) (string, error) {
if store == nil {
return "", fmt.Errorf("storage not initialized: open the database before resolving IDs")
}
return utils.ResolvePartialID(ctx, store, input)
} Type guard
func storeReady(store utils.PartialIDResolverStore) bool { return store != nil } Try / catch
id, err := utils.ResolvePartialID(ctx, store, input)
if err != nil {
if strings.Contains(err.Error(), "storage is nil") {
return fmt.Errorf("run 'bd init' or open the database first: %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: Calling ResolvePartialID(ctx, nil, input) — directly or via ResolvePartialID(s) — before a store/database handle has been opened or assigned.
Common situations: 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.
Related errors
- %w. Hint: run 'bd init' to create a database in the current
- no store available
- resolving molecule ID %s: %w
- no database connection
- proxied-server UOW provider not initialized
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/86607e9bdc4982bf.
Report an issue: GitHub.