{"record":{"id":"61c59b0f8b597e74","repo":"OrchardCMS/OrchardCore","slug":"a-duplicate-key-key-was-found","errorCode":null,"errorMessage":"A duplicate key '{key}' was found.","messagePattern":"A duplicate key '(.+?)' was found\\.","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/Internal/JsonConfigurationParser.cs","lineNumber":160,"sourceCode":"                break;\n\n            case JsonValueKind.Number:\n            case JsonValueKind.String:\n            case JsonValueKind.True:\n            case JsonValueKind.False:\n            case JsonValueKind.Null:\n\n                // Skipping null values is useful to override array items,\n                // it allows to keep non null items at the right position.\n                if (visitArray && value.ValueKind == JsonValueKind.Null)\n                {\n                    break;\n                }\n\n                var key = _paths.Peek();\n                if (_data.ContainsKey(key))\n                {\n                    throw new FormatException($\"A duplicate key '{key}' was found.\");\n                }\n                _data[key] = value.ToString();\n                break;\n\n            default:\n                throw new FormatException($\"Unsupported JSON token '{value.ValueKind}' was found.\");\n        }\n    }\n\n    private void EnterContext(string context) =>\n        _paths.Push(_paths.Count > 0 ?\n            _paths.Peek() + ConfigurationPath.KeyDelimiter + context :\n            context);\n\n    private void ExitContext() => _paths.Pop();\n}\n","sourceCodeStart":142,"sourceCodeEnd":177,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/Internal/JsonConfigurationParser.cs#L142-L177","documentation":"While flattening the JSON document, VisitValue stores each scalar under the current property path. Because the internal dictionary is case-insensitive, encountering the same effective path twice (e.g. 'Foo' and 'foo' as sibling keys, or a key appearing at the same nested path) raises FormatException 'A duplicate key was found.' Configuration keys must be unique per path.","triggerScenarios":"Calling JsonConfigurationParser.Parse/ParseAsync with a document containing two properties that normalize to the same path, like {\"Key\": \"a\", \"key\": \"b\"} or duplicated keys after case-insensitive comparison in nested objects.","commonSituations":"Merged appsettings where an object was accidentally duplicated at the same level; hand-merged JSON that kept both old and new copies of a section; code generators emitting the same property twice with different casing.","solutions":["Remove or rename one of the duplicated keys so each path is unique","Search the JSON for repeated property names differing only by case","If merging documents, merge objects key-by-key instead of concatenating properties","Validate uniqueness (case-insensitive) before parsing"],"exampleFix":"// before\n{\"ConnectionStrings\": {\"Default\": \"a\"}, \"connectionstrings\": {\"default\": \"b\"}}\n// after\n{\"ConnectionStrings\": {\"Default\": \"b\"}}","handlingStrategy":"validation","validationCode":"using var doc = JsonDocument.Parse(document, JOptions.Document);\nvar seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);\nvoid Walk(JsonElement e, string path)\n{\n    if (e.ValueKind != JsonValueKind.Object) return;\n    foreach (var p in e.EnumerateObject())\n    {\n        var key = path + \":\" + p.Name;\n        if (!seen.Add(key)) throw new InvalidDataException($\"Duplicate key '{key}'\");\n        Walk(p.Value, key);\n    }\n}\nWalk(doc.RootElement, \"\");","typeGuard":null,"tryCatchPattern":"try { JsonConfigurationParser.Parse(document); }\ncatch (FormatException ex) when (ex.Message.StartsWith(\"A duplicate key\"))\n{ log.LogError(ex, \"Remove duplicated property in config JSON\"); }","preventionTips":["Never merge JSON objects by concatenating properties","Detect duplicate keys with a case-insensitive pre-parse check","Search for sibling properties differing only by case","Keep one canonical source for each settings section"],"tags":["json","configuration","duplicate-key"],"backgroundTag":"schema-validation-failed","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}