gastownhall/beads · error
failed to write config.yaml: %w
Error message
failed to write config.yaml: %w
What it means
The final step of SetReposInYAML writes the re-encoded YAML back to config.yaml with os.WriteFile using mode 0600. If the write fails, the error is wrapped as "failed to write config.yaml". Note the write happens only after encode+close succeed, so the data itself is valid.
Source
Thrown at internal/config/repos.go:152
&yaml.Node{Kind: yaml.ScalarNode, Value: "repos"},
reposNode,
)
}
// Marshal back to YAML
var buf strings.Builder
encoder := yaml.NewEncoder(&buf)
encoder.SetIndent(2)
if err := encoder.Encode(&root); err != nil {
return fmt.Errorf("failed to encode config.yaml: %w", err)
}
if err := encoder.Close(); err != nil {
return fmt.Errorf("failed to close encoder: %w", err)
}
// Write back to file
if err := os.WriteFile(configPath, []byte(buf.String()), 0600); err != nil {
return fmt.Errorf("failed to write config.yaml: %w", err)
}
// Reload viper config so changes take effect immediately
if v != nil {
if err := v.ReadInConfig(); err != nil {
// Not fatal - config is on disk, will be picked up on next command
_ = err // Best effort: viper reload failure is non-fatal since config was already written to disk
}
}
return nil
}
// buildReposNode creates a yaml.Node for the repos configuration
// Returns nil if repos is empty (no primary and no additional)
func buildReposNode(repos *ReposConfig) *yaml.Node {
if repos == nil || (repos.Primary == "" && len(repos.Additional) == 0) {
return nilView on GitHub (pinned to 71377f2769)
Solutions
- Check permissions on config.yaml and its parent directory; chown/chmod as needed
- Free disk space or check quota (df -h, quota)
- Ensure the filesystem is writable (not a read-only mount)
- Delete and recreate the file if ownership is wrong (a new file gets correct owner)
Example fix
// before // file owned by root, running as user -> permission denied // after sudo chown $(whoami) ~/.config/bd/config.yaml bd repo add /path/to/repo
Defensive patterns
Strategy: validation
Validate before calling
d := filepath.Dir(configPath)
if fi, err := os.Stat(d); err != nil || !fi.IsDir() || fi.Mode().Perm()&0200 == 0 {
return fmt.Errorf("config dir %s not writable", d)
} Type guard
func isWritableDir(p string) bool {
fi, err := os.Stat(p)
return err == nil && fi.IsDir() && fi.Mode().Perm()&0200 != 0
} Try / catch
if err := SetReposInYAML(cfgPath, repos); err != nil {
if strings.Contains(err.Error(), "failed to write") {
log.Printf("check ownership/permissions/disk on %s: %v", cfgPath, err)
}
return err
} Prevention
- Ensure the same OS user owns config.yaml and runs bd
- Keep config directories writable (avoid read-only mounts for mutable config)
- Monitor disk space/quota
- Prefer recreating the file over chmod-ing foreign-owned files
When it happens
Trigger: os.WriteFile(configPath, ...) fails — directory not writable, disk full, permission denied (existing file owned by another user — WriteFile does not chown), or read-only filesystem.
Common situations: Running bd as a different user than the one who owns config.yaml (0600 means only the owner can write), disk quota exceeded, or config directory mounted read-only (e.g. container with read-only volume).
Related errors
- write metadata.json: %w
- failed to save config: %w
- failed to set beads.role config: %w
- failed to write config.yaml: %w
- failed to read config.yaml: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c0349e96115d0bfa.
Report an issue: GitHub.