{"record":{"id":"bac2c97664cb61bd","repo":"gastownhall/beads","slug":"no-storage-backend-is-open","errorCode":null,"errorMessage":"no storage backend is open","messagePattern":"no storage backend is open","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/backup_dolt.go","lineNumber":363,"sourceCode":"\tresult[\"backup_url\"] = cfg.BackupURL\n\tresult[\"backup_name\"] = cfg.BackupName\n\tresult[\"created_at\"] = cfg.CreatedAt.Format(time.RFC3339)\n\n\tstate, err := loadDoltBackupState()\n\tif err == nil && state != nil {\n\t\tresult[\"last_sync\"] = state.LastSync.Format(time.RFC3339)\n\t\tresult[\"sync_duration\"] = state.Duration\n\t}\n\n\treturn result\n}\n\n// doltBackupSize returns the active database size when the current store\n// instance can measure its storage locally. Unsupported backends preserve the\n// optional status-field contract instead of failing the command.\nfunc doltBackupSize(ctx context.Context) (int64, bool, error) {\n\tif store == nil {\n\t\treturn 0, false, fmt.Errorf(\"no storage backend is open\")\n\t}\n\treturn doltBackupSizeForStore(ctx, store)\n}\n\nfunc doltBackupSizeForStore(ctx context.Context, candidate storage.DoltStorage) (int64, bool, error) {\n\tsizer, ok := storage.UnwrapStore(candidate).(storage.ActiveDatabaseSizer)\n\tif !ok {\n\t\treturn 0, false, nil\n\t}\n\treturn doltBackupSizeFromSizer(ctx, sizer)\n}\n\nfunc doltBackupSizeFromSizer(ctx context.Context, sizer storage.ActiveDatabaseSizer) (int64, bool, error) {\n\tsize, err := sizer.ActiveDatabaseSize(ctx)\n\tif err != nil {\n\t\tvar unsupported *storage.ErrUnsupported\n\t\tif errors.As(err, &unsupported) {\n\t\t\treturn 0, false, nil","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/backup_dolt.go#L345-L381","documentation":"doltBackupSize reports the size of the active Dolt database through the globally-open store instance. If the package-level `store` variable is nil — no storage backend has been opened for this process — it returns the error 'no storage backend is open'. This guards against calling the sizer interface (ActiveDatabaseSizer) on a nil store, which would panic.","triggerScenarios":"Invoking bd backup commands that query database size (e.g. `bd backup` status paths calling doltBackupSize) when `store` was never initialized via bd's database-open (ensureStore/open) path, e.g. running with flags that skip DB opening or before the daemon/router opens the store.","commonSituations":"Backup subcommands run in contexts where the DB was not opened first (scripted misuse of internal helpers, tests that forgot store setup), or a code regression where the store-open step was skipped before sizing.","solutions":["Ensure the bd command opens the database (routes through the normal command bootstrap) before requesting backup size","If calling internals from tests, initialize the global store (or use doltBackupSizeForStore with a real storage.DoltStorage) before calling doltBackupSize","Check for recent code changes that bypassed the store-open step"],"exampleFix":"// before\ncount, hasSize, err := doltBackupSize(ctx) // store is nil\n// after\nensureStoreOpen(ctx) // or construct store first\nif store == nil {\n    return fmt.Errorf(\"open the database before requesting backup size\")\n}\ncount, hasSize, err := doltBackupSize(ctx)","handlingStrategy":"type-guard","validationCode":"if store == nil {\n    // open the store or skip size reporting before calling doltBackupSize\n    return 0, false, errors.New(\"open the storage backend first\")\n}","typeGuard":"func storeOpen(s storage.DoltStorage) bool { return s != nil }\n// call site:\nif !storeOpen(store) { /* initialize or skip */ }","tryCatchPattern":"size, ok, err := doltBackupSize(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"no storage backend is open\") {\n        // degrade gracefully: omit size from status output\n        return nil\n    }\n    return err\n}","preventionTips":["Route all store-touching code through the standard command bootstrap that opens the store","In tests, seed the global store or use doltBackupSizeForStore with an explicit store","Treat size reporting as optional (the bool return) and never require it"],"tags":["go","storage","dolt"],"backgroundTag":"store-not-initialized","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}