{"record":{"id":"408aaab8988eea59","repo":"elsa-workflows/elsa-core","slug":"expected-startobject-token","errorCode":null,"errorMessage":"Expected StartObject token","messagePattern":"Expected StartObject token","errorType":"validation","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs","lineNumber":15,"sourceCode":"using System.Text.Json;\nusing System.Text.Json.Serialization;\n\nnamespace Elsa.Http.Serialization;\n\n/// <summary>\n/// A custom JSON converter for HttpHeaders that supports both single and multiple values.\n/// </summary>\npublic class HttpHeadersConverter : JsonConverter<HttpHeaders>\n{\n    /// <inheritdoc />\n    public override HttpHeaders Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType != JsonTokenType.StartObject)\n            throw new JsonException(\"Expected StartObject token\");\n\n        var headers = new HttpHeaders();\n\n        while (reader.Read())\n        {\n            if (reader.TokenType == JsonTokenType.EndObject)\n                return headers;\n\n            if (reader.TokenType != JsonTokenType.PropertyName)\n                throw new JsonException(\"Expected a PropertyName token\");\n\n            var key = reader.GetString()!;\n            reader.Read();\n\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:","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs#L1-L33","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the JSON value for HttpHeaders is an object like {\"Accept\":[\"text/plain\"]}, not an array or string","Fix the source that produced the malformed JSON (e.g. double-serializing headers into a string)","Add a try/catch around JsonSerializer.Deserialize<HttpHeaders> and reject/log the payload","Pre-validate with JsonDocument that the token at the headers position is JsonValueKind.Object"],"exampleFix":"// before\nvar headers = JsonSerializer.Deserialize<HttpHeaders>(\"[{\\\"Accept\\\":[\\\"text/plain\\\"]}]\");\n// after\nvar headers = JsonSerializer.Deserialize<HttpHeaders>(\"{\\\"Accept\\\":[\\\"text/plain\\\"]}\");","handlingStrategy":"type-guard","validationCode":"using var doc = JsonDocument.Parse(json);\nif (doc.RootElement.ValueKind != JsonValueKind.Object)\n    throw new FormatException(\"Headers payload must be a JSON object\");","typeGuard":"bool IsHttpHeadersPayload(JsonElement e) => e.ValueKind == JsonValueKind.Object && e.EnumerateObject().All(p => p.Value.ValueKind is JsonValueKind.String or JsonValueKind.Array);","tryCatchPattern":"try { headers = JsonSerializer.Deserialize<HttpHeaders>(json, options); }\ncatch (JsonException ex)\n{\n    logger.LogWarning(ex, \"Malformed HttpHeaders JSON\");\n    headers = new HttpHeaders();\n}","preventionTips":["Always serialize headers through the HttpHeaders type, never hand-build the JSON","Validate payload shape with JsonDocument before deserializing untrusted input","Pin one serializer configuration so headers are written consistently across versions"],"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"}