elsa-workflows/elsa-core · error · InvalidOperationException

The Platform shell overlay file must contain a JSON object.

Error message

The Platform shell overlay file must contain a JSON object.

What it means

FileShellConfigurationOverlayStore.LoadAsync reads the shell overlay file and parses it with JsonNode.ParseAsync, then casts to JsonObject. If the file's top-level JSON value is not an object (e.g. an array, string, or number), the cast fails and this InvalidOperationException is thrown.

Solutions

  1. Edit the overlay file so its root is a JSON object, e.g. { }. Validate with a JSON parser.
  2. Delete or rename the malformed file; LoadAsync recreates an empty JsonObject when the file is absent.
  3. Restore the file from backup or regenerate it by re-saving the overlay through the integration.

Example fix

// before (shell-overlay.json)
[]
// after (shell-overlay.json)
{}
Defensive patterns

Strategy: try-catch

Validate before calling

using var doc = JsonDocument.Parse(await File.ReadAllTextAsync(overlayPath));
if (doc.RootElement.ValueKind != JsonValueKind.Object)
    throw new InvalidOperationException("Overlay file root must be a JSON object.");

Type guard

bool IsValidOverlayRoot(JsonNode? node) => node is JsonObject;

Try / catch

try { var root = await store.LoadAsync(ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("must contain a JSON object"))
{
    logger.LogWarning(ex, "Overlay file malformed; starting from empty overlay.");
    root = new JsonObject();
}

Prevention

When it happens

Trigger: The file at ShellOverlayPath exists and contains valid JSON whose root is not an object — for example '[ ]' or '"text"' — and LoadAsync is invoked during overlay load.

Common situations: A user hand-edited the overlay file into an array; an export tool wrote a different JSON shape; the file was overwritten by another process with the wrong schema.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/5ae1afcca9607a94. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Platform.Integration/Services/FileShellConfigurationOverlayStore.cs:82

                Merge(configuration, settingsObject);

            return await SaveIfChangedAsync(root, before, cancellationToken);
        }
        finally
        {
            _semaphore.Release();
        }
    }

    private async Task<JsonObject> LoadAsync(CancellationToken cancellationToken)
    {
        var path = GetPath();
        if (!File.Exists(path))
            return new JsonObject();

        await using var stream = File.OpenRead(path);
        return await JsonNode.ParseAsync(stream, cancellationToken: cancellationToken) as JsonObject
            ?? throw new InvalidOperationException("The Platform shell overlay file must contain a JSON object.");
    }

    private async Task<bool> SaveIfChangedAsync(JsonObject root, string before, CancellationToken cancellationToken)
    {
        var after = Serialize(root);
        if (string.Equals(before, after, StringComparison.Ordinal))
            return false;

        var path = GetPath();
        var directory = Path.GetDirectoryName(path);
        if (!string.IsNullOrWhiteSpace(directory))
            Directory.CreateDirectory(directory);

        var tempPath = $"{path}.{Guid.NewGuid():N}.tmp";
        await File.WriteAllTextAsync(tempPath, after, cancellationToken);
        File.Move(tempPath, path, overwrite: true);
        return true;
    }

View on GitHub (pinned to fe9217bdfa)