{"record":{"id":"1ea3fa10fef59dc4","repo":"elsa-workflows/elsa-core","slug":"expected-an-endobject-token","errorCode":null,"errorMessage":"Expected an EndObject token","messagePattern":"Expected an EndObject token","errorType":"validation","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs","lineNumber":51,"sourceCode":"                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        }\n\n        writer.WriteEndObject();\n    }\n}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Http/Serialization/HttpHeadersConverter.cs#L33-L69","documentation":"HttpHeadersConverter.Read builds an HttpHeaders instance from JSON while walking object tokens. When it reaches the end of the JSON buffer without having consumed the expected EndObject token, it throws this JsonException. It means the JSON being deserialized is malformed or truncated - an object was opened but never closed, or a scalar/arrays appeared where object syntax was required.","triggerScenarios":"Deserializing a payload containing an HttpHeaders-typed property where the JSON object is unterminated (e.g. '{\"Authorization\": [\"Bearer x\"]' missing the closing '}'), or where the reader hits end-of-input inside the object, such as during model binding of HTTP header sets in workflows or API endpoints.","commonSituations":"Truncated request bodies from proxies or clients, hand-crafted JSON in workflow definition files, copy-pasted JSON missing a closing brace, or a converter/serializer mismatch where a non-object value (string/array) is supplied for an HttpHeaders property (that path throws the sibling 'Expected a String or StartArray token' error instead).","solutions":["Validate the JSON payload with a parser (e.g. JsonDocument.Parse in a try/catch) before passing it to deserialization to pinpoint the syntax error.","Ensure every object opened in the JSON for HttpHeaders-typed properties is closed with '}'.","Check that the serialized data was not truncated in transit (log/inspect raw payload length and tail).","If using custom serialization pipelines, make sure Utf8JsonReader input spans contain the complete document (utf8 bytes not sliced mid-object)."],"exampleFix":"// before\nvar headers = JsonSerializer.Deserialize<HttpHeaders>(truncatedJson);\n// after\nJsonDocument doc;\ntry { doc = JsonDocument.Parse(json); }\ncatch (JsonException ex) { throw new FormatException($\"Malformed JSON payload: {ex.Message}\", ex); }\nvar headers = doc.RootElement.ValueKind == JsonValueKind.Object\n    ? JsonSerializer.Deserialize<HttpHeaders>(json)\n    : throw new FormatException(\"Expected a JSON object for HttpHeaders\");","handlingStrategy":"validation","validationCode":"static bool IsValidHttpHeadersJson(string json)\n{\n    try\n    {\n        using var doc = JsonDocument.Parse(json);\n        return doc.RootElement.ValueKind == JsonValueKind.Object;\n    }\n    catch (JsonException) { return false; }\n}","typeGuard":"static bool IsHttpHeadersObject(JsonElement el) => el.ValueKind == JsonValueKind.Object && el.EnumerateObject().All(p => p.Value.ValueKind is JsonValueKind.String or JsonValueKind.Array);","tryCatchPattern":"try { var headers = JsonSerializer.Deserialize<HttpHeaders>(json, options); }\ncatch (JsonException ex) when (ex.Message.Contains(\"EndObject\"))\n{\n    logger.LogError(ex, \"Malformed/truncated JSON for HttpHeaders\");\n}","preventionTips":["Round-trip test serialized payloads with JsonDocument.Parse before storing or sending them.","Never build JSON by string concatenation; use Utf8JsonWriter or model serialization.","Check for truncation at network boundaries (Content-Length vs received bytes)."],"tags":["json","deserialization","system-text-json","malformed-input"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}