gastownhall/beads · error

failed to read config.yaml: %w

Error message

failed to read config.yaml: %w

What it means

setYamlConfigAtPath wraps any os.ReadFile failure on the target config.yaml path before updating a key. The wrapped cause (%w) is the underlying OS error, so the real reason (missing file, permissions, path) is in the %w suffix. bd throws it because YAML config writes require reading the existing file to merge the new key into it.

Source

Thrown at internal/config/yaml_config.go:515

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		if err := os.WriteFile(configPath, []byte{}, 0o600); err != nil {
			return fmt.Errorf("failed to create user config.yaml: %w", err)
		}
	} else if err != nil {
		return fmt.Errorf("failed to stat user config.yaml: %w", err)
	}
	return setYamlConfigAtPath(configPath, key, value)
}

func setYamlConfigAtPath(configPath, key, value string) error {

	// Normalize key to canonical yaml format
	normalizedKey := normalizeYamlKey(key)

	// Read existing config
	content, err := os.ReadFile(configPath) //nolint:gosec // configPath is from findProjectConfigYaml
	if err != nil {
		return fmt.Errorf("failed to read config.yaml: %w", err)
	}

	// Update or add the key
	newContent, err := updateYamlKey(string(content), normalizedKey, value)
	if err != nil {
		return err
	}

	// Write back
	if err := os.WriteFile(configPath, []byte(newContent), 0600); err != nil { //nolint:gosec // configPath is validated
		return fmt.Errorf("failed to write config.yaml: %w", err)
	}

	return nil
}

// GetYamlConfig gets a configuration value from config.yaml.
// Returns empty string if key is not found or is commented out.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run 'bd init' in the project (or in the directory BEADS_DIR points at) to create .beads/config.yaml
  2. Check the wrapped error in the %w suffix: if 'no such file or directory', create the file; if 'permission denied', fix ownership/permissions (chmod/chown)
  3. Verify BEADS_DIR points to the correct directory containing config.yaml, or unset it to use project resolution
  4. Ensure config.yaml is a regular readable file, not a directory, symlink, or FIFO

Example fix

// before (fails: file never created)
BEADS_DIR=/tmp/myrepo bd config set dolt.mode embedded
// after
bd init /tmp/myrepo && bd config set dolt.mode embedded
Defensive patterns

Strategy: try-catch

Validate before calling

path, err := findProjectConfigYaml()
if err != nil { return err }
if _, err := os.Stat(path); err != nil {
    return fmt.Errorf("config.yaml missing at %s: run 'bd init' first", path)
}

Type guard

func configReadable(path string) bool {
    fi, err := os.Stat(path)
    return err == nil && fi.Mode().IsRegular()
}

Try / catch

if err := SetYamlConfig(key, value); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && os.IsNotExist(err) {
        // run bd init or create config.yaml, then retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetYamlConfig, SetYamlConfigInDir, or SetUserYamlConfig when the resolved config.yaml path does not exist (project not initialized) or cannot be opened (permissions, path is a directory, race where the file is deleted between resolution and read).

Common situations: Running 'bd config set' in a repo where 'bd init' was never run; BEADS_DIR pointing at a directory without config.yaml; config.yaml with restrictive ownership after switching users or cloning without the file.

Related errors


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