gastownhall/beads · error
write metadata.json: %w
Error message
write metadata.json: %w
What it means
In `finalizeSyncedBootstrap`, after a synced bootstrap the config (`metadata.json`) is updated so the database field points at the Dolt database name (defaulting to `"dolt"` rather than the legacy placeholder). If `cfg.Save(beadsDir)` fails to write metadata.json, the error is wrapped as `write metadata.json: ...` and bootstrap finalization aborts.
Source
Thrown at cmd/bd/bootstrap.go:835
// required by configfile.Load consumers.
cfg.Backend = configfile.BackendDolt
cfg.DoltDatabase = dbName
switch {
case cfg.IsDoltProxiedServerMode():
cfg.DoltMode = configfile.DoltModeProxiedServer
case cfg.IsDoltServerMode() || doltserver.IsSharedServerMode():
cfg.DoltMode = configfile.DoltModeServer
default:
cfg.DoltMode = configfile.DoltModeEmbedded
}
// Mirror init's convention: metadata.json database points at the Dolt
// directory rather than the legacy "beads.db" placeholder.
if cfg.Database == "" || cfg.Database == beads.CanonicalDatabaseName {
cfg.Database = "dolt"
}
if err := cfg.Save(beadsDir); err != nil {
return fmt.Errorf("write metadata.json: %w", err)
}
if err := createConfigYaml(beadsDir, false, ""); err != nil {
return fmt.Errorf("create config.yaml: %w", err)
}
if err := doctor.EnsureGitignoreForBeadsDir(beadsDir); err != nil {
return fmt.Errorf("ensure .beads/.gitignore: %w", err)
}
// Persist sync.remote so subsequent fresh clones (and bd bootstrap
// retries) can rediscover the remote without re-probing origin refs.
if syncRemote != "" {
if err := config.SetYamlConfigInDir(beadsDir, "sync.remote", syncRemote); err != nil {
return fmt.Errorf("persist sync.remote to config.yaml: %w", err)
}
}
return nilView on GitHub (pinned to 71377f2769)
Solutions
- Check writability of `.beads/metadata.json`: fix ownership/permissions (`chown -R $USER .beads`).
- If metadata.json is a directory or corrupt, remove it and re-run `bd bootstrap` (it will rewrite config files).
- Free disk space if the wrapped error reports I/O or no-space failures.
- Re-run `bd bootstrap` — finalization is designed to be idempotent (see TestFinalizeSyncedBootstrapIsIdempotent).
Example fix
// before (shell) $ sudo bd bootstrap # .beads now owned by root $ bd bootstrap // write metadata.json: open ...: permission denied // after $ sudo chown -R $USER .beads $ bd bootstrap # succeeds
Defensive patterns
Strategy: validation
Validate before calling
# Pre-flight before finalize (bootstrap) runs:
BEADS_DIR=.beads
[ -d "$BEADS_DIR" ] || { echo "missing $BEADS_DIR"; exit 1; }
if [ -e "$BEADS_DIR/metadata.json" ] && [ -d "$BEADS_DIR/metadata.json" ]; then echo "metadata.json is a directory"; exit 1; fi
[ -w "$BEADS_DIR" ] || { echo "$BEADS_DIR not writable by $(whoami)"; exit 1; } Try / catch
if err := finalizeSyncedBootstrap(ctx, beadsDir, plan, cfg); err != nil {
if strings.Contains(err.Error(), "write metadata.json:") {
// finalization is idempotent — fix permissions and re-run bootstrap
return fmt.Errorf("repair .beads permissions, then re-run bd bootstrap: %w", err)
}
return err
} Prevention
- Avoid running bootstrap under sudo; if you must, chown `.beads` back afterwards.
- Ensure `.beads/metadata.json` is a regular writable file, not a directory.
- Check disk space before long-running bootstrap operations.
- Re-running `bd bootstrap` after fixing permissions is safe (idempotent finalization).
When it happens
Trigger: `bd bootstrap` finishing a sync action calls `finalizeSyncedBootstrap`; saving the updated config fails — `.beads` directory not writable, disk full, metadata.json exists as a directory, or permission conflicts.
Common situations: Read-only or root-owned `.beads` after cloning with sudo; a stray `metadata.json/` directory; interrupted earlier bootstrap leaving bad permissions; CI running as a different user than the clone owner.
Related errors
- create beads directory: %w
- create config.yaml: %w
- failed to save config: %w
- failed to set beads.role config: %w
- failed to write config.yaml: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6f0b9a53155ae061.
Report an issue: GitHub.