{"record":{"id":"0fb917a6ce5b343e","repo":"gastownhall/beads","slug":"error-merging-local-config-file-w","errorCode":null,"errorMessage":"error merging local config file: %w","messagePattern":"error merging local config file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config.go","lineNumber":383,"sourceCode":"\t\tfor _, p := range configPaths[1:] {\n\t\t\tv.SetConfigFile(p)\n\t\t\tif err := v.MergeInConfig(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error merging config file %s: %w\", p, err)\n\t\t\t}\n\t\t\tdebug.Logf(\"Debug: merged config from %s\\n\", p)\n\t\t}\n\n\t\t// Restore primary config path as ConfigFileUsed (used by SaveConfigValue,\n\t\t// ResolveExternalProjectPath, etc.)\n\t\tv.SetConfigFile(primaryConfigPath)\n\n\t\t// Merge local config overrides if present (config.local.yaml)\n\t\t// This allows machine-specific settings without polluting tracked config\n\t\tlocalConfigPath := filepath.Join(filepath.Dir(primaryConfigPath), \"config.local.yaml\")\n\t\tif _, err := os.Stat(localConfigPath); err == nil {\n\t\t\tv.SetConfigFile(localConfigPath)\n\t\t\tif err := v.MergeInConfig(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error merging local config file: %w\", err)\n\t\t\t}\n\t\t\tdebug.Logf(\"Debug: merged local config from %s\\n\", localConfigPath)\n\t\t\t// Restore primary as ConfigFileUsed\n\t\t\tv.SetConfigFile(primaryConfigPath)\n\t\t}\n\t} else {\n\t\t// No config.yaml found - use defaults and environment variables\n\t\tdebug.Logf(\"Debug: no config.yaml found; using defaults and environment variables\\n\")\n\t}\n\n\treturn nil\n}\n\n// ResetForTesting clears the config state, allowing Initialize() to be called again.\n// This is intended for tests that need to change config.yaml between test steps.\n// WARNING: Not thread-safe. Only call from single-threaded test contexts.\nfunc ResetForTesting() {\n\tv = nil","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/config.go#L365-L401","documentation":"Initialize merges an optional machine-local override file, config.local.yaml, sitting next to the primary config, and wraps any MergeInConfig failure from it. It means the local override exists but could not be read or parsed. The viper cause is preserved via %w.","triggerScenarios":"A config.local.yaml exists in the same directory as the primary config, and its YAML is invalid or the file is unreadable when Initialize runs.","commonSituations":"A developer hand-edits config.local.yaml for machine-specific settings (API keys, paths) and introduces a YAML typo; the file is copied between machines with different encodings; a lockfile-style collision leaves it half-written.","solutions":["Open config.local.yaml (path shown via debug log, next to your primary config) and fix the YAML syntax.","Check file permissions on config.local.yaml.","If the overrides are not needed, delete or rename config.local.yaml so it is skipped by the os.Stat check.","Validate with a YAML parser before saving, e.g. `yamllint config.local.yaml`."],"exampleFix":"// before (config.local.yaml)\nai:\n  api_key: \"sk-... # missing closing quote\n// after\nai:\n  api_key: \"sk-...\"","handlingStrategy":"validation","validationCode":"local := filepath.Join(filepath.Dir(primaryConfigPath), \"config.local.yaml\")\nif _, err := os.Stat(local); err == nil {\n    var m map[string]interface{}\n    data, _ := os.ReadFile(local)\n    if err := yaml.Unmarshal(data, &m); err != nil {\n        return fmt.Errorf(\"fix %s before starting: %w\", local, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := config.Initialize(paths); err != nil {\n    if strings.Contains(err.Error(), \"config.local\") {\n        log.Warn(\"local override broken, ignoring\", \"err\", err)\n        os.Rename(local, local+\".broken\")\n        err = config.Initialize(paths)\n    }\n    return err\n}","preventionTips":["Treat config.local.yaml like source code: lint it after every hand edit.","Keep local overrides tiny — only keys that must differ per machine.","Use an editor with YAML syntax highlighting; avoid copy-paste of secrets with quotes.","Add config.local.yaml checks to your dev-env setup script."],"tags":["config","yaml","local-override","viper"],"backgroundTag":"config-file-parse-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}