gastownhall/beads · error
error reading config file: %w
Error message
error reading config file: %w
What it means
Initialize wraps any error returned by viper's ReadInConfig when loading the first (primary) config file. It means the primary config file exists but could not be read or parsed — bad YAML syntax, unreadable permissions, or a directory passed as a config path. The underlying viper error is preserved via %w so callers can inspect the cause.
Source
Thrown at internal/config/config.go:361
v.SetDefault("ai.base_url", "")
// List command defaults
v.SetDefault("list.limit", 50)
// Output configuration (GH#1384)
// Controls title display in command feedback messages.
// 0 = hide title, N > 0 = truncate to N chars with "…"
v.SetDefault("output.title-length", 255)
// External projects for cross-project dependency resolution (bd-h807)
// Maps project names to paths for resolving external: blocked_by references
v.SetDefault("external_projects", map[string]string{})
// Load config files: lowest priority first, each MergeInConfig overwrites
if len(configPaths) > 0 {
v.SetConfigFile(configPaths[0])
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("error reading config file: %w", err)
}
debug.Logf("Debug: loaded config from %s\n", configPaths[0])
for _, p := range configPaths[1:] {
v.SetConfigFile(p)
if err := v.MergeInConfig(); err != nil {
return fmt.Errorf("error merging config file %s: %w", p, err)
}
debug.Logf("Debug: merged config from %s\n", p)
}
// Restore primary config path as ConfigFileUsed (used by SaveConfigValue,
// ResolveExternalProjectPath, etc.)
v.SetConfigFile(primaryConfigPath)
// Merge local config overrides if present (config.local.yaml)
// This allows machine-specific settings without polluting tracked config
localConfigPath := filepath.Join(filepath.Dir(primaryConfigPath), "config.local.yaml")View on GitHub (pinned to 71377f2769)
Solutions
- Open the file named in the wrapped error and fix the YAML syntax (validate with yamllint or a YAML parser).
- Check file permissions and ownership: ensure the current user can read the file.
- Verify the path points to a regular file, not a directory or symlink to a missing target.
- If the file is unrecoverable, restore it from version control or a backup, or delete it so defaults are used.
Example fix
// before (config.yaml) routing: mode: auto # tab indentation breaks YAML // after routing: mode: auto # use spaces
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(configPath)
if err != nil { return err }
if info.IsDir() { return fmt.Errorf("%s is a directory, not a file", configPath) }
data, err := os.ReadFile(configPath)
if err != nil { return err }
if err := yaml.Unmarshal(data, map[string]interface{}{}); err != nil {
return fmt.Errorf("config %s has invalid YAML: %w", configPath, err)
} Try / catch
if err := config.Initialize(paths); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) {
log.Fatalf("cannot read %s: %v — fix or remove the file", perr.Path, perr.Err)
}
return err
} Prevention
- Validate config files with a YAML linter in CI or a git pre-commit hook.
- Keep config files in version control so bad edits are diff-visible and revertible.
- Write config files atomically (temp file + rename) to avoid truncated files.
- Ensure the service user owns or can read all config paths.
When it happens
Trigger: Calling Initialize with a configPaths[0] file that is malformed YAML, has no read permission, is a directory, or an empty/corrupt file that viper's ReadInConfig rejects.
Common situations: Hand-edited config.yaml with broken indentation or tabs; a config file truncated by a crashed editor or disk-full write; permissions changed by another user; passing a path with the wrong extension or encoding (UTF-16, BOM issues).
Related errors
- error merging config file %s: %w
- error merging local config file: %w
- failed to parse config.yaml: %w
- persist sync.remote to config.yaml: %w
- failed to persist sync.remote to config.yaml: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c5b3ffba24633894.
Report an issue: GitHub.