{"record":{"id":"217d3b18615ee687","repo":"googleapis/mcp-toolbox","slug":"unable-to-merge-config-files-w","errorCode":null,"errorMessage":"unable to merge config files: %w","messagePattern":"unable to merge config files: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/internal/config.go","lineNumber":527,"sourceCode":"\t\tbuf, err := os.ReadFile(filePath)\n\t\tif err != nil {\n\t\t\treturn Config{}, fmt.Errorf(\"unable to read config file at %q: %w\", filePath, err)\n\t\t}\n\n\t\tconfig, err := p.ParseConfig(ctx, buf)\n\t\tif err != nil {\n\t\t\treturn Config{}, fmt.Errorf(\"unable to parse config file at %q: %w\", filePath, err)\n\t\t}\n\n\t\tconfigs = append(configs, config)\n\t}\n\tif len(configs) == 0 {\n\t\treturn Config{}, fmt.Errorf(\"no YAML files found\")\n\t}\n\tif len(configs) > 1 {\n\t\tmergedFile, err := mergeConfigs(configs...)\n\t\tif err != nil {\n\t\t\treturn Config{}, fmt.Errorf(\"unable to merge config files: %w\", err)\n\t\t}\n\t\treturn mergedFile, nil\n\t}\n\treturn configs[0], nil\n}\n\n// GetPathsFromConfigFolder loads all YAML files from a directory and merges them\nfunc GetPathsFromConfigFolder(ctx context.Context, folderPath string) ([]string, error) {\n\t// Check if directory exists\n\tinfo, err := os.Stat(folderPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to access config folder at %q: %w\", folderPath, err)\n\t}\n\tif !info.IsDir() {\n\t\treturn nil, fmt.Errorf(\"path %q is not a directory\", folderPath)\n\t}\n\n\t// Find all YAML files in the directory","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/cmd/internal/config.go#L509-L545","documentation":"When more than one config was loaded, mergeConfigs combines them; any error from the merge (duplicate names, multiple mcpEnabled authServices) is wrapped as 'unable to merge config files' with the underlying reason.","triggerScenarios":"LoadAndMergeConfigs with len(configs) > 1 where mergeConfigs returns an error — typically duplicate resource names across files or conflicting MCP auth servers.","commonSituations":"Combining prebuilt configs with custom files that share tool/source names; passing overlapping config files twice.","solutions":["Read the wrapped cause to find the conflict (usually duplicate names)","Rename duplicates so each source/tool/authService/prompt/group is unique","Deduplicate the list of config files being passed"],"exampleFix":"// before\ntoolbox --config-file a.yaml --config-file a.yaml\n// after\ntoolbox --config-file a.yaml --config-file b.yaml","handlingStrategy":"validation","validationCode":"if hasDuplicates(filePaths) {\n  return fmt.Errorf(\"duplicate config files passed: %v\", filePaths)\n}\n// plus pre-check for duplicate resource names as in error 22","typeGuard":null,"tryCatchPattern":"cfg, err := parser.LoadAndMergeConfigs(ctx, files)\nif err != nil {\n  if strings.Contains(err.Error(), \"unable to merge config files\") {\n    var mergeErr error\n    if errors.Unwrap(err) != nil { mergeErr = errors.Unwrap(err) }\n    // inspect mergeErr for the specific conflict\n  }\n  return err\n}","preventionTips":["Deduplicate the config file list before merging","Give resources unique names across all files","Test multi-file merges in CI with the same files used in production"],"tags":["config-merge","multi-file","naming-conflict"],"backgroundTag":"config-merge-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}