OrchardCMS/OrchardCore · error · FormatException

Top level JSON element must be an object. Instead

Error message

Top level JSON element must be an object. Instead, {jsonNode.GetValueKind()} was found.

What it means

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.

Solutions

  1. Ensure the configuration root only has named (non-numeric) keys; rename numeric keys to named ones.
  2. Call ToJsonObject on a specific object-shaped section: configuration.GetSection("MyObject").ToJsonObject().
  3. If the data is genuinely an array, use ToJsonNode() and handle the JsonArray result instead.
  4. Sanitize provider keys (e.g. environment variables) so indexed entries aren't at the root.

Example fix

// before
var obj = envDrivenConfig.ToJsonObject(); // root keys: 0,1,2
// after
var obj = envDrivenConfig.GetSection("Settings").ToJsonObject();
Defensive patterns

Strategy: validation

Validate before calling

var children = configuration.GetChildren().ToList();
if (children.Any(c => int.TryParse(c.Key, out _))) throw new FormatException("Root configuration must have named keys, not numeric indexes.");

Type guard

bool IsObjectShaped(IConfiguration c) => c.GetChildren().All(ch => !int.TryParse(ch.Key, out _));

Try / catch

try { var obj = configuration.ToJsonObject(); }
catch (FormatException ex) when (ex.Message.StartsWith("Top level JSON element")) { var node = configuration.ToJsonNode(); /* handle array root */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/bdd5e3078a60d9a0. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.Abstractions/Shell/Configuration/Internal/ConfigurationExtensions.cs:14

using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Extensions.Configuration;

namespace OrchardCore.Environment.Shell.Configuration.Internal;

public static class ConfigurationExtensions
{
    public static JsonObject ToJsonObject(this IConfiguration configuration)
    {
        var jsonNode = ToJsonNode(configuration);
        if (jsonNode is not JsonObject jObject)
        {
            throw new FormatException($"Top level JSON element must be an object. Instead, {jsonNode.GetValueKind()} was found.");
        }

        return jObject;
    }

    public static JsonNode ToJsonNode(this IConfiguration configuration)
    {
        JsonArray jArray = null;
        JsonObject jObject = null;

        foreach (var child in configuration.GetChildren())
        {
            if (int.TryParse(child.Key, out var index))
            {
                if (jObject is not null)
                {
                    throw new FormatException($"Can't use the numeric key '{child.Key}' inside an object.");
                }

View on GitHub (pinned to 4306c0717f)