gastownhall/beads · error

reading legacy config: %w

Error message

reading legacy config: %w

What it means

Load wraps a non-ENOENT os.ReadFile failure of the legacy .beads/config.json with "reading legacy config: %w". A missing legacy file is treated as no legacy config; this error means the file exists but is unreadable, blocking the migrate-to-metadata.json path.

Source

Thrown at internal/configfile/configfile.go:94

}

func ConfigPath(beadsDir string) string {
	return filepath.Join(beadsDir, ConfigFileName)
}

func Load(beadsDir string) (*Config, error) {
	configPath := ConfigPath(beadsDir)

	data, err := os.ReadFile(configPath) // #nosec G304 - controlled path from config
	if os.IsNotExist(err) {
		// 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
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix permissions: `chmod u+r .beads/config.json` and confirm ownership
  2. Verify it is a regular file, not a directory or symlink to a missing target
  3. If the migration already completed, the legacy file can be archived/removed after confirming metadata.json exists

Example fix

// before
-rw------- root config.json   # owned by root, unreadable
// after
sudo chown $USER .beads/config.json && chmod u+rw .beads/config.json
Defensive patterns

Strategy: try-catch

Validate before calling

fi, err := os.Stat(filepath.Join(".beads", "config.json"))
if err == nil && (!fi.Mode().IsRegular() || fi.Mode().Perm()&0o400 == 0) {
    // legacy config unreadable: fix permissions before running bd
}

Try / catch

cfg, err := bd.Load(cfgOpts)
if err != nil {
    if errors.Is(err, fs.ErrPermission) { /* chown/chmod .beads/config.json */ }
    return err
}

Prevention

When it happens

Trigger: Load(config) when .beads/config.json exists but cannot be read — permission denied, it is a directory, or an I/O error occurs during the migration check.

Common situations: Legacy config left read-only after copying a workspace as another user; config.json partially restored from backup with broken permissions; disk/device errors.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b79ebe72b84ec681. Report an issue: GitHub.