{"record":{"id":"db86a00f08183760","repo":"gastownhall/beads","slug":"storage-backend-has-no-underlying-database","errorCode":null,"errorMessage":"storage backend has no underlying database","messagePattern":"storage backend has no underlying database","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/validation.go","lineNumber":30,"sourceCode":"\t\"github.com/steveyegge/beads/internal/configfile\"\n\t\"github.com/steveyegge/beads/internal/storage\"\n\t\"github.com/steveyegge/beads/internal/storage/dolt\"\n)\n\n// openStoreDB opens the beads database and returns the underlying *sql.DB for\n// raw queries. The caller must close the returned store when done.\nfunc openStoreDB(beadsDir string) (*sql.DB, storage.DoltStorage, error) {\n\tctx := context.Background()\n\tdoltPath := getDatabasePath(beadsDir)\n\tcfg := doltServerConfig(beadsDir, doltPath)\n\tstore, err := dolt.New(ctx, cfg)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tdb := store.UnderlyingDB()\n\tif db == nil {\n\t\t_ = store.Close() // Best effort cleanup\n\t\treturn nil, nil, fmt.Errorf(\"storage backend has no underlying database\")\n\t}\n\treturn db, store, nil\n}\n\n// CheckOrphanedDependencies detects dependencies pointing to non-existent issues.\nfunc CheckOrphanedDependencies(path string) DoctorCheck {\n\tbeadsDir := ResolveBeadsDirForRepo(path)\n\n\tdb, store, err := openStoreDB(beadsDir)\n\tif err != nil {\n\t\treturn DoctorCheck{\n\t\t\tName:    \"Orphaned Dependencies\",\n\t\t\tStatus:  \"ok\",\n\t\t\tMessage: \"N/A (no database)\",\n\t\t}\n\t}\n\tdefer func() { _ = store.Close() }()\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/validation.go#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nDoctorCheck := CheckDuplicateIssues(path) // works only for SQL backends\n// after\nif store.UnderlyingDB() != nil {\n    DoctorCheck = CheckDuplicateIssues(path)\n} else { /* file-based check */ }","handlingStrategy":"type-guard","validationCode":"store, err := openStore(path)\nif err == nil && store.UnderlyingDB() == nil {\n    // non-SQL backend: use file-based checks instead\n}","typeGuard":"func hasUnderlyingDB(s storage.Store) bool { return s != nil && s.UnderlyingDB() != nil }","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no underlying database\") {\n    // fall back to JSONL/file-based validation path\n}","preventionTips":["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"],"tags":["beads","storage","backend","doctor"],"backgroundTag":"no-underlying-database","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}