gastownhall/beads · error
loading config: %w
Error message
loading config: %w
What it means
guardLegacyUpgradeWorkspace loads the workspace config via configfile.LoadForDiscovery and wraps any load failure as "loading config: %w". Called before any upgrade/guard decision (doctor validation, legacy workspace discovery), it protects against unreadable or malformed config in the .beads directory. The root cause (parse error, IO error, schema error) is preserved in the chain.
Source
Thrown at cmd/bd/legacy_upgrade_guard.go:31
"github.com/steveyegge/beads/internal/doltserver"
"github.com/steveyegge/beads/internal/git"
"github.com/steveyegge/beads/internal/storage/embeddeddolt"
"github.com/steveyegge/beads/internal/utils"
"golang.org/x/mod/semver"
)
// guardLegacyUpgradeWorkspace rejects the reviewed pre-Dolt and legacy-Dolt
// workspace shapes before command setup can track a version, migrate metadata,
// or construct a store. It intentionally classifies only metadata, regular
// SQLite files, and the bounded local version witness; storage internals stay
// behind the driver boundary.
func guardLegacyUpgradeWorkspace(beadsDir string) error {
if beadsDir == "" {
return nil
}
cfg, err := configfile.LoadForDiscovery(beadsDir)
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
if isHistoricalSQLiteWorkspace(beadsDir, cfg) {
return legacyUpgradeRefusal("historical SQLite workspace")
}
// Validate read-only discovery metadata before any caller can use Load,
// which migrates legacy config.json to metadata.json. Removed and unknown
// backends must fail without changing the only pointer to their data.
if err := validateConfiguredBackend(cfg); err != nil {
return err
}
serverMode := cfg != nil && strings.EqualFold(cfg.DoltMode, configfile.DoltModeServer)
if embeddeddolt.HasRepository(beadsDir) && !serverMode {
return nil
}
version, present := legacyUpgradeVersionWitness(beadsDir)
if serverMode && present && legacyServerVersion(version) {
return legacyUpgradeRefusal(fmt.Sprintf("legacy Dolt server workspace from bd %s", version))
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped root cause — usually a JSON parse or file permission error naming the config file
- Validate/repair the JSON in .beads/metadata.json (or legacy config.json); restore from git if the workspace is tracked
- Check file permissions/ownership of the .beads directory
- If migrating from legacy SQLite, back up .beads and let the upgrade tooling regenerate config
Example fix
// before (malformed)
{"database": "beads.db",,}
// after
{"database": "beads.db"} Defensive patterns
Strategy: validation
Validate before calling
// pre-validate workspace config JSON before running guarded commands python3 -m json.tool .beads/metadata.json > /dev/null || echo "config JSON is malformed"
Try / catch
if err := guardLegacyUpgradeWorkspace(beadsDir); err != nil {
var perr *json.SyntaxError
if errors.As(err, &perr) { /* repair JSON at perr.Offset */ }
return err
} Prevention
- Don't hand-edit .beads config files without validating JSON afterward
- Track .beads config in git so you can restore a known-good version
- Check file permissions on .beads before running doctor/upgrade commands
- Back up .beads before any legacy SQLite to Dolt migration
When it happens
Trigger: Running bd commands that hit guardLegacyUpgradeWorkspace (doctor workspace validation, upgrade guards) in a workspace whose config.json/metadata.json cannot be loaded — malformed JSON, unreadable file, or discovery-time validation failure.
Common situations: Hand-edited config.json with JSON syntax errors; .beads directory with wrong permissions; partially migrated workspace mixing legacy and new config files; interrupted upgrade leaving truncated metadata.json.
Related errors
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/04f19474a313af2f.
Report an issue: GitHub.