{"record":{"id":"2717a42e0d730d22","repo":"gastownhall/beads","slug":"error-merging-config-file-s-w","errorCode":null,"errorMessage":"error merging config file %s: %w","messagePattern":"error merging config file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/config.go","lineNumber":368,"sourceCode":"\t// 0 = hide title, N > 0 = truncate to N chars with \"…\"\n\tv.SetDefault(\"output.title-length\", 255)\n\n\t// External projects for cross-project dependency resolution (bd-h807)\n\t// Maps project names to paths for resolving external: blocked_by references\n\tv.SetDefault(\"external_projects\", map[string]string{})\n\n\t// Load config files: lowest priority first, each MergeInConfig overwrites\n\tif len(configPaths) > 0 {\n\t\tv.SetConfigFile(configPaths[0])\n\t\tif err := v.ReadInConfig(); err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config file: %w\", err)\n\t\t}\n\t\tdebug.Logf(\"Debug: loaded config from %s\\n\", configPaths[0])\n\n\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","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/config.go#L350-L386","documentation":"Initialize wraps errors from viper's MergeInConfig when merging each additional config file after the first. It means one of the overlay config paths exists but could not be parsed or read; the failing path is interpolated into the message. The viper cause is wrapped with %w.","triggerScenarios":"Initialize receives multiple config paths; a path at index >= 1 points to a file with invalid YAML, wrong permissions, or an unreadable directory.","commonSituations":"Team overlays (e.g. per-environment config files) that diverge in schema; a CI-generated overlay written as JSON with a syntax error; a second config file made read-only by a package manager.","solutions":["Fix the YAML in the specific file named in the error message (validate with a YAML linter).","Check read permissions on that overlay file for the running user.","Remove or rename the broken overlay file if it is no longer needed; Initialize tolerates missing later paths only if your code filters them beforehand.","Diff the overlay against the primary config to spot schema drift that breaks parsing."],"exampleFix":"// before\nbd config add ./prod-overlay.yaml  # file contains: {routing: mode:} \n// after\n# prod-overlay.yaml\nrouting:\n  mode: auto","handlingStrategy":"validation","validationCode":"for _, p := range overlayPaths {\n    data, err := os.ReadFile(p)\n    if err != nil { return err }\n    var m map[string]interface{}\n    if err := yaml.Unmarshal(data, &m); err != nil {\n        return fmt.Errorf(\"overlay %s invalid: %w\", p, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := config.Initialize(paths); err != nil {\n    if strings.Contains(err.Error(), \"error merging config file\") {\n        // extract path from message or re-run per-file to isolate\n        log.Fatalf(\"bad overlay config: %v\", err)\n    }\n    return err\n}","preventionTips":["Lint every overlay file in CI, not just the primary config.","Keep overlays minimal and schema-checked against the primary config.","Regenerate CI-produced overlays atomically to avoid half-written files.","Diff overlays against the primary when upgrading versions."],"tags":["config","yaml","merge","viper"],"backgroundTag":"config-file-parse-error","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}