gastownhall/beads · error
migrating config to metadata.json: %w
Error message
migrating config to metadata.json: %w
What it means
During the legacy config.json -> metadata.json migration inside Load(), after successfully parsing the legacy file, bd writes the migrated config with Config.Save. This error wraps any failure of that save (temp-file creation, write, chmod, rename inside the beads directory). The migration aborts and the legacy file is left in place, so the next Load retries the migration.
Source
Thrown at internal/configfile/configfile.go:105
// Try legacy config.json location (migration path)
legacyPath := filepath.Join(beadsDir, "config.json")
data, err = os.ReadFile(legacyPath) // #nosec G304 - controlled path from config
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("reading legacy config: %w", err)
}
// Migrate: parse legacy config, save as metadata.json, remove old file
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing legacy config: %w", err)
}
// Save to new location
if err := cfg.Save(beadsDir); err != nil {
return nil, fmt.Errorf("migrating config to metadata.json: %w", err)
}
// Remove legacy file (best effort: migration already saved to new location)
_ = os.Remove(legacyPath)
return &cfg, nil
}
if err != nil {
return nil, fmt.Errorf("reading config: %w", err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing config: %w", err)
}
return &cfg, nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Check write permissions on the .beads directory (ls -ld .beads) and fix with chown/chmod
- Free disk space if the filesystem is full
- Remove stale metadata.json.tmp-* files, then rerun bd
- If the directory is intentionally read-only, migrate the config on a writable machine or run bd once with elevated access
Example fix
// before $ bd ready Error: parsing... migrating config to metadata.json: permission denied // after $ chmod u+w .beads && bd ready
Defensive patterns
Strategy: try-catch
Validate before calling
info, err := os.Stat(beadsDir)
if err != nil || !info.IsDir() {
return fmt.Errorf("beads dir missing")
}
if f, err := os.OpenFile(filepath.Join(beadsDir, ".write-probe"), os.O_CREATE|os.O_WRONLY, 0o600); err != nil {
return fmt.Errorf("beads dir not writable: %w", err)
} else {
f.Close(); os.Remove(filepath.Join(beadsDir, ".write-probe"))
} Try / catch
cfg, err := configfile.Load(beadsDir)
if err != nil && strings.Contains(err.Error(), "migrating config to metadata.json") {
// check disk space and .beads permissions, then retry Load
err = retryLoad(beadsDir)
} Prevention
- Keep .beads owned by the user running bd
- Monitor disk space in CI runners
- Avoid read-only mounts for workspaces that must migrate
- Complete the migration once on a writable machine before distributing the workspace
When it happens
Trigger: Calling configfile.Load(beadsDir) when metadata.json is missing, config.json parses fine, but Save fails because the beads dir is read-only, disk is full, permissions deny writing metadata.json, or .beads was deleted between read and save.
Common situations: Read-only checkouts or mounted volumes; .beads owned by another user; disk quota exceeded; a stale metadata.json.tmp-* left by a crashed process (harmless, but a full filesystem is not).
Related errors
- write metadata.json: %w
- failed to save config: %w
- failed to set beads.role config: %w
- failed to write config.yaml: %w
- checking destination sidecar %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/08275aa923b83d6d.
Report an issue: GitHub.