{"record":{"id":"bdd5e3078a60d9a0","repo":"OrchardCMS/OrchardCore","slug":"top-level-json-element-must-be-an-object-instead-jsonnode","errorCode":null,"errorMessage":"Top level JSON element must be an object. Instead, {jsonNode.GetValueKind()} was found.","messagePattern":"Top level JSON element must be an object\\. Instead, (.+?) was found\\.","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/Internal/ConfigurationExtensions.cs","lineNumber":14,"sourceCode":"using System.Text.Json;\nusing System.Text.Json.Nodes;\nusing Microsoft.Extensions.Configuration;\n\nnamespace OrchardCore.Environment.Shell.Configuration.Internal;\n\npublic static class ConfigurationExtensions\n{\n    public static JsonObject ToJsonObject(this IConfiguration configuration)\n    {\n        var jsonNode = ToJsonNode(configuration);\n        if (jsonNode is not JsonObject jObject)\n        {\n            throw new FormatException($\"Top level JSON element must be an object. Instead, {jsonNode.GetValueKind()} was found.\");\n        }\n\n        return jObject;\n    }\n\n    public static JsonNode ToJsonNode(this IConfiguration configuration)\n    {\n        JsonArray jArray = null;\n        JsonObject jObject = null;\n\n        foreach (var child in configuration.GetChildren())\n        {\n            if (int.TryParse(child.Key, out var index))\n            {\n                if (jObject is not null)\n                {\n                    throw new FormatException($\"Can't use the numeric key '{child.Key}' inside an object.\");\n                }","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/Internal/ConfigurationExtensions.cs#L1-L32","documentation":"ToJsonObject converts an IConfiguration tree to a JsonObject by first building a JsonNode. Because configuration is expected to be a flat key/value mapping, the root node must be an object; if the root turned out to be an array or value, the method throws FormatException.","triggerScenarios":"Calling configuration.ToJsonObject() on a configuration whose root children parse as numeric keys (e.g. keys '0','1','2' from indexed sections), causing ToJsonNode to build a JsonArray at the root.","commonSituations":"Serializing a configuration section that stores a list under numeric keys (command-line args, environment variables like 'MyList__0'), or piping a sub-section of array-shaped data to ToJsonObject.","solutions":["Ensure the configuration root only has named (non-numeric) keys; rename numeric keys to named ones.","Call ToJsonObject on a specific object-shaped section: configuration.GetSection(\"MyObject\").ToJsonObject().","If the data is genuinely an array, use ToJsonNode() and handle the JsonArray result instead.","Sanitize provider keys (e.g. environment variables) so indexed entries aren't at the root."],"exampleFix":"// before\nvar obj = envDrivenConfig.ToJsonObject(); // root keys: 0,1,2\n// after\nvar obj = envDrivenConfig.GetSection(\"Settings\").ToJsonObject();","handlingStrategy":"validation","validationCode":"var children = configuration.GetChildren().ToList();\nif (children.Any(c => int.TryParse(c.Key, out _))) throw new FormatException(\"Root configuration must have named keys, not numeric indexes.\");","typeGuard":"bool IsObjectShaped(IConfiguration c) => c.GetChildren().All(ch => !int.TryParse(ch.Key, out _));","tryCatchPattern":"try { var obj = configuration.ToJsonObject(); }\ncatch (FormatException ex) when (ex.Message.StartsWith(\"Top level JSON element\")) { var node = configuration.ToJsonNode(); /* handle array root */ }","preventionTips":["Ensure root config keys are named, not numeric indexes","Use GetSection() to pick object-shaped subtrees","Inspect GetDebugView() when config shapes look wrong"],"tags":["configuration","json","format"],"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-16T04:17:20.429Z"}