gastownhall/beads · error

failed to write config.yaml: %w

Error message

failed to write config.yaml: %w

What it means

setYamlConfigAtPath wraps any os.WriteFile failure after successfully computing the updated YAML content. The file was read fine but writing the merged content back failed; the OS-level cause is preserved via %w. bd throws it because a failed write would silently drop the config change.

Source

Thrown at internal/config/yaml_config.go:526

	// 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.
// Keys are normalized to their canonical yaml format (e.g., sync.branch -> sync-branch).
func GetYamlConfig(key string) string {
	if v == nil {
		return ""
	}
	normalizedKey := normalizeYamlKey(key)
	return v.GetString(normalizedKey)
}

// UnsetYamlConfig removes a configuration value from the project's config.yaml file.
// The key line is commented out (prefixed with "# ") to preserve it as documentation.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped cause: 'permission denied' -> chmod/chown config.yaml so the current user can write (chmod u+w .beads/config.yaml)
  2. Free disk space or resolve quota if the cause is ENOSPC
  3. Ensure config.yaml is a regular file, not a directory or broken symlink
  4. Re-run the command with the appropriate user/credentials (e.g., not sudo-stripped ownership)

Example fix

// before (fails: read-only file)
$ bd config set dolt.shared-server false
failed to write config.yaml: ... permission denied
// after
$ chmod u+w .beads/config.yaml
$ bd config set dolt.shared-server false
Defensive patterns

Strategy: try-catch

Validate before calling

fi, err := os.Stat(configPath)
if err != nil || !fi.Mode().IsRegular() {
    return fmt.Errorf("config.yaml not writable-regular: %s", configPath)
}
if err := syscall.Access(configPath, syscall.O_RDWR); err != nil {
    return fmt.Errorf("no write permission on %s", configPath)
}

Type guard

func configWritable(path string) bool {
    f, err := os.OpenFile(path, os.O_WRONLY, 0)
    if err != nil { return false }
    f.Close()
    return true
}

Try / catch

if err := SetYamlConfig(key, value); err != nil {
    if errors.Is(err, os.ErrPermission) { /* fix perms */ }
    if errors.Is(err, syscall.ENOSPC) { /* free disk */ }
    return err
}

Prevention

When it happens

Trigger: Calling SetYamlConfig / SetYamlConfigInDir / SetUserYamlConfig when the config.yaml file or its containing directory is read-only, the disk is full, the path became a directory, or the process lacks write permission (mode 0600 write by a different user).

Common situations: Running bd as a non-root user against a root-owned config.yaml; read-only mount or checked-out repo with read-only .beads/config.yaml; disk quota exceeded in CI containers.

Related errors


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