gastownhall/beads · error

failed to write user config.yaml: %w

Error message

failed to write user config.yaml: %w

What it means

After reading and transforming the user config.yaml (commenting out the key), UnsetUserYamlConfig rewrites the file with os.WriteFile using 0600 to preserve the owner-private posture. Any write failure (permissions, read-only filesystem, disk full) is wrapped as 'failed to write user config.yaml'.

Source

Thrown at internal/config/yaml_config.go:480

		return err
	}
	normalizedKey := normalizeYamlKey(key)

	content, err := os.ReadFile(configPath) //nolint:gosec // configPath is a validated absolute user config path
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return fmt.Errorf("failed to read user config.yaml: %w", err)
	}

	newContent := commentOutYamlKey(string(content), normalizedKey)

	// Preserve the owner-private 0600 posture every other user-global writer
	// uses (SetUserYamlConfig, setYamlConfigAtPath, the metrics bootstrap);
	// rewriting at 0644 would relax this shared user config to world-readable.
	if err := os.WriteFile(configPath, []byte(newContent), 0o600); err != nil { //nolint:gosec // configPath is from UserConfigYamlPath
		return fmt.Errorf("failed to write user config.yaml: %w", err)
	}

	return nil
}

func SetUserYamlConfig(key, value string) error {
	if err := validateYamlConfigValue(key, value); err != nil {
		return err
	}
	configPath, err := UserConfigYamlPath()
	if err != nil {
		return err
	}
	if err := os.MkdirAll(filepath.Dir(configPath), 0o755); err != nil {
		return fmt.Errorf("failed to create user config directory: %w", err)
	}
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		if err := os.WriteFile(configPath, []byte{}, 0o600); err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix ownership/permissions: chown $USER ~/.beads/config.yaml && chmod 600 ~/.beads/config.yaml.
  2. Ensure the filesystem is writable (remount rw, exit read-only CI workspace).
  3. Check disk space/quota: df -h ~/.beads; free space and retry.
  4. Inspect the wrapped %w cause for the exact OS error (EACCES, EROFS, ENOSPC) and address it.

Example fix

// before
-rw------- root root ~/.beads/config.yaml
bd config unset metrics.enabled  // EACCES
// after
sudo chown $USER:$USER ~/.beads/config.yaml
bd config unset metrics.enabled
Defensive patterns

Strategy: try-catch

Validate before calling

dir := filepath.Dir(userConfigPath)
if err := unix.Access(dir, unix.W_OK); err != nil {
    return fmt.Errorf("cannot write %s: %w", dir, err)
}
if fi, err := os.Stat(userConfigPath); err == nil && fi.Mode().Perm() != 0o600 {
    os.Chmod(userConfigPath, 0o600)
}

Try / catch

err := config.UnsetUserYamlConfig(key)
var pe *fs.PathError
if errors.As(err, &pe) {
    switch {
    case errors.Is(pe.Err, fs.ErrPermission): return fixOwnership(pe.Path)
    case errors.Is(pe.Err, syscall.ENOSPC): return freeDiskAndRetry()
    default: return pe
    }
}

Prevention

When it happens

Trigger: os.WriteFile on the validated user config path fails: file or parent directory not writable by the current user, filesystem mounted read-only, immutable file attribute, or ENOSPC.

Common situations: Root-owned ~/.beads/config.yaml after a sudo run; disk quota exceeded; editing config on a read-only bind mount or CI workspace checked out read-only.

Related errors


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