elsa-workflows/elsa-core · error · JsonException

Expected StartObject token

Error message

Expected StartObject token

What it means

HttpHeadersConverter is a System.Text.Json JsonConverter for the HttpHeaders type, which models headers as name-to-array-of-values. Its Read method only accepts a JSON object at the top level, so any other leading token raises JsonException('Expected StartObject token').

Solutions

  1. Ensure the JSON value for HttpHeaders is an object like {"Accept":["text/plain"]}, not an array or string
  2. Fix the source that produced the malformed JSON (e.g. double-serializing headers into a string)
  3. Add a try/catch around JsonSerializer.Deserialize<HttpHeaders> and reject/log the payload
  4. Pre-validate with JsonDocument that the token at the headers position is JsonValueKind.Object

Example fix

// before
var headers = JsonSerializer.Deserialize<HttpHeaders>("[{\"Accept\":[\"text/plain\"]}]");
// after
var headers = JsonSerializer.Deserialize<HttpHeaders>("{\"Accept\":[\"text/plain\"]}");
Defensive patterns

Strategy: type-guard

Validate before calling

using var doc = JsonDocument.Parse(json);
if (doc.RootElement.ValueKind != JsonValueKind.Object)
    throw new FormatException("Headers payload must be a JSON object");

Type guard

bool IsHttpHeadersPayload(JsonElement e) => e.ValueKind == JsonValueKind.Object && e.EnumerateObject().All(p => p.Value.ValueKind is JsonValueKind.String or JsonValueKind.Array);

Try / catch

try { headers = JsonSerializer.Deserialize<HttpHeaders>(json, options); }
catch (JsonException ex)
{
    logger.LogWarning(ex, "Malformed HttpHeaders JSON");
    headers = new HttpHeaders();
}

Prevention

When it happens

Trigger: Deserializing a property typed as HttpHeaders from JSON that is an array, string, number, or null instead of an object — e.g. persisted workflow state or an API payload where headers were stored as "[{...}]" or as a raw string.

Common situations: Hand-edited or migrated workflow instance state; older/other serializer versions that wrote headers differently; sending headers JSON built with an array wrapper by client code.

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/408aaab8988eea59. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs:15

using System.Text.Json;
using System.Text.Json.Serialization;

namespace Elsa.Http.Serialization;

/// <summary>
/// A custom JSON converter for HttpHeaders that supports both single and multiple values.
/// </summary>
public class HttpHeadersConverter : JsonConverter<HttpHeaders>
{
    /// <inheritdoc />
    public override HttpHeaders Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
            throw new JsonException("Expected StartObject token");

        var headers = new HttpHeaders();

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
                return headers;

            if (reader.TokenType != JsonTokenType.PropertyName)
                throw new JsonException("Expected a PropertyName token");

            var key = reader.GetString()!;
            reader.Read();

            // If the next token is not a StartArray token, then we expect a String token.
            switch (reader.TokenType)
            {
                case JsonTokenType.StartArray:

View on GitHub (pinned to fe9217bdfa)