gastownhall/beads · error
storage backend has no underlying database
Error message
storage backend has no underlying database
What it means
openStoreDB opens the beads storage store and fetches its underlying *sql.DB via store.UnderlyingDB(). Some backends have no SQL database underneath; if the handle is nil the store is closed and this error returned, since the SQL-level checks cannot run.
Source
Thrown at cmd/bd/doctor/validation.go:30
"github.com/steveyegge/beads/internal/configfile"
"github.com/steveyegge/beads/internal/storage"
"github.com/steveyegge/beads/internal/storage/dolt"
)
// openStoreDB opens the beads database and returns the underlying *sql.DB for
// raw queries. The caller must close the returned store when done.
func openStoreDB(beadsDir string) (*sql.DB, storage.DoltStorage, error) {
ctx := context.Background()
doltPath := getDatabasePath(beadsDir)
cfg := doltServerConfig(beadsDir, doltPath)
store, err := dolt.New(ctx, cfg)
if err != nil {
return nil, nil, err
}
db := store.UnderlyingDB()
if db == nil {
_ = store.Close() // Best effort cleanup
return nil, nil, fmt.Errorf("storage backend has no underlying database")
}
return db, store, nil
}
// CheckOrphanedDependencies detects dependencies pointing to non-existent issues.
func CheckOrphanedDependencies(path string) DoctorCheck {
beadsDir := ResolveBeadsDirForRepo(path)
db, store, err := openStoreDB(beadsDir)
if err != nil {
return DoctorCheck{
Name: "Orphaned Dependencies",
Status: "ok",
Message: "N/A (no database)",
}
}
defer func() { _ = store.Close() }()
View on GitHub (pinned to 71377f2769)
Solutions
- Switch the repository to a Dolt backend so an underlying SQL database exists
- Skip database-level checks for non-SQL backends and use file-based validations instead
- Check store construction/initialization if a Dolt backend unexpectedly returns nil
Example fix
// before
DoctorCheck := CheckDuplicateIssues(path) // works only for SQL backends
// after
if store.UnderlyingDB() != nil {
DoctorCheck = CheckDuplicateIssues(path)
} else { /* file-based check */ } Defensive patterns
Strategy: type-guard
Validate before calling
store, err := openStore(path)
if err == nil && store.UnderlyingDB() == nil {
// non-SQL backend: use file-based checks instead
} Type guard
func hasUnderlyingDB(s storage.Store) bool { return s != nil && s.UnderlyingDB() != nil } Try / catch
if err != nil && strings.Contains(err.Error(), "no underlying database") {
// fall back to JSONL/file-based validation path
} Prevention
- Check the configured backend before running SQL-backed doctor checks
- Use file-based validations for the JSONL backend
- In tests, build stores backed by a real (e.g. in-memory SQL) DB when exercising these checks
When it happens
Trigger: Calling openStoreDB (directly or via CheckStaleClosedIssues, CheckOrphanedDependencies, CheckDuplicateIssues, CheckTestPollution, CheckChildParentDependencies, wisp misclassification checks) on a backend whose UnderlyingDB() returns nil — e.g. JSONL/file backend.
Common situations: Repo configured for the JSONL (non-Dolt) backend while running database-backed doctor validations; embedded/mock store in tests lacking a DB; storage factory returning a wrapper without DB support.
Related errors
- not using Dolt backend (configured backend %q)
- no .beads/ directory found at %s; run 'bd init' to initializ
- running performance diagnostics: %w
- Dolt server performance diagnostics do not apply to the conf
- node %q: adding parent-child dep: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/db86a00f08183760.
Report an issue: GitHub.