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
- Fix ownership/permissions: chown $USER ~/.beads/config.yaml && chmod 600 ~/.beads/config.yaml.
- Ensure the filesystem is writable (remount rw, exit read-only CI workspace).
- Check disk space/quota: df -h ~/.beads; free space and retry.
- 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
- Run bd as the owning user; fix with chown after accidental sudo use.
- Keep the user home on a writable, non-quota-exhausted filesystem.
- Preserve 0600 mode when editing user config.yaml externally (e.g. umask 077).
- Check disk space (df -h ~) when writes fail mysteriously.
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
- writing config: %w
- write metadata.json: %w
- failed to save config: %w
- failed to write .gitignore: %w
- failed to set beads.role config: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b56bd67fb51e0874.
Report an issue: GitHub.