elsa-workflows/elsa-core · error · JsonException

Expected a String or StartArray token

Error message

Expected a String or StartArray token

What it means

After reading a header key, HttpHeadersConverter only accepts either a single String token or a StartArray token (for multiple values). Any other token — number, boolean, nested object, null — triggers JsonException('Expected a String or StartArray token'), because header values must be strings or arrays of strings.

Solutions

  1. Convert header values to strings (or arrays of strings) in the JSON: {"Content-Length": "123"}
  2. Fix the producer to serialize header values via ToString before writing JSON
  3. Validate the payload shape with JsonDocument before calling Deserialize<HttpHeaders>
  4. Catch JsonException around deserialization and log the offending header key

Example fix

// before
{"Content-Length": 123}
// after
{"Content-Length": "123"}
Defensive patterns

Strategy: type-guard

Validate before calling

using var doc = JsonDocument.Parse(json);
foreach (var prop in doc.RootElement.EnumerateObject())
{
    var ok = prop.Value.ValueKind == JsonValueKind.String
        || (prop.Value.ValueKind == JsonValueKind.Array && prop.Value.EnumerateArray().All(v => v.ValueKind == JsonValueKind.String));
    if (!ok) throw new FormatException($"Header '{prop.Name}' must be a string or array of strings");
}

Type guard

bool IsStringOrStringArray(JsonElement v) => v.ValueKind == JsonValueKind.String || (v.ValueKind == JsonValueKind.Array && v.EnumerateArray().All(x => x.ValueKind == JsonValueKind.String));

Try / catch

try { headers = JsonSerializer.Deserialize<HttpHeaders>(json, options); }
catch (JsonException ex)
{
    logger.LogWarning(ex, "Header value was not a string or string array");
    throw;
}

Prevention

When it happens

Trigger: Deserializing HttpHeaders where a header value is a non-string/non-array, e.g. {"Content-Length": 123} or {"X-Custom": {"a":1}} — common when JSON was generated by code that didn't stringify values.

Common situations: Client/API payloads built with numeric or boolean header values; serializer output from a different HttpHeaders representation; hand-edited workflow state.

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/09c26e9d28f8feed. Report an issue: GitHub.

Appendix: source

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

            // If the next token is not a StartArray token, then we expect a String token.
            switch (reader.TokenType)
            {
                case JsonTokenType.StartArray:
                {
                    var values = new List<string>();
                    while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) values.Add(reader.GetString()!);
                    headers.Add(key, values.ToArray());
                    break;
                }
                case JsonTokenType.String:
                {
                    var singleValue = reader.GetString()!;
                    headers.Add(key, new[] { singleValue });
                    break;
                }
                default:
                    throw new JsonException("Expected a String or StartArray token");
            }
        }

        throw new JsonException("Expected an EndObject token");
    }

    /// <inheritdoc />
    public override void Write(Utf8JsonWriter writer, HttpHeaders value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        foreach (var header in value)
        {
            writer.WritePropertyName(header.Key);
            writer.WriteStartArray();
            foreach (var headerValue in header.Value) writer.WriteStringValue(headerValue);
            writer.WriteEndArray();
        }

View on GitHub (pinned to fe9217bdfa)