{"record":{"id":"09c26e9d28f8feed","repo":"elsa-workflows/elsa-core","slug":"expected-a-string-or-startarray-token","errorCode":null,"errorMessage":"Expected a String or StartArray token","messagePattern":"Expected a String or StartArray token","errorType":"validation","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs","lineNumber":47,"sourceCode":"\n            // If the next token is not a StartArray token, then we expect a String token.\n            switch (reader.TokenType)\n            {\n                case JsonTokenType.StartArray:\n                {\n                    var values = new List<string>();\n                    while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) values.Add(reader.GetString()!);\n                    headers.Add(key, values.ToArray());\n                    break;\n                }\n                case JsonTokenType.String:\n                {\n                    var singleValue = reader.GetString()!;\n                    headers.Add(key, new[] { singleValue });\n                    break;\n                }\n                default:\n                    throw new JsonException(\"Expected a String or StartArray token\");\n            }\n        }\n\n        throw new JsonException(\"Expected an EndObject token\");\n    }\n\n    /// <inheritdoc />\n    public override void Write(Utf8JsonWriter writer, HttpHeaders value, JsonSerializerOptions options)\n    {\n        writer.WriteStartObject();\n\n        foreach (var header in value)\n        {\n            writer.WritePropertyName(header.Key);\n            writer.WriteStartArray();\n            foreach (var headerValue in header.Value) writer.WriteStringValue(headerValue);\n            writer.WriteEndArray();\n        }","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"Client/API payloads built with numeric or boolean header values; serializer output from a different HttpHeaders representation; hand-edited workflow state.","solutions":["Convert header values to strings (or arrays of strings) in the JSON: {\"Content-Length\": \"123\"}","Fix the producer to serialize header values via ToString before writing JSON","Validate the payload shape with JsonDocument before calling Deserialize<HttpHeaders>","Catch JsonException around deserialization and log the offending header key"],"exampleFix":"// before\n{\"Content-Length\": 123}\n// after\n{\"Content-Length\": \"123\"}","handlingStrategy":"type-guard","validationCode":"using var doc = JsonDocument.Parse(json);\nforeach (var prop in doc.RootElement.EnumerateObject())\n{\n    var ok = prop.Value.ValueKind == JsonValueKind.String\n        || (prop.Value.ValueKind == JsonValueKind.Array && prop.Value.EnumerateArray().All(v => v.ValueKind == JsonValueKind.String));\n    if (!ok) throw new FormatException($\"Header '{prop.Name}' must be a string or array of strings\");\n}","typeGuard":"bool IsStringOrStringArray(JsonElement v) => v.ValueKind == JsonValueKind.String || (v.ValueKind == JsonValueKind.Array && v.EnumerateArray().All(x => x.ValueKind == JsonValueKind.String));","tryCatchPattern":"try { headers = JsonSerializer.Deserialize<HttpHeaders>(json, options); }\ncatch (JsonException ex)\n{\n    logger.LogWarning(ex, \"Header value was not a string or string array\");\n    throw;\n}","preventionTips":["Always convert header values with ToString() before serializing","Reject numeric/boolean/object header values at your API boundary","Document that HttpHeaders maps to string | string[] per key in any client SDKs"],"tags":["json","serialization","http","elsa"],"backgroundTag":"json-parse-error","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}