{"record":{"id":"665e4b9092c13106","repo":"elsa-workflows/elsa-core","slug":"failed-to-parse-jsondocument-flowchartjsonconverter","errorCode":null,"errorMessage":"Failed to parse JsonDocument","messagePattern":"Failed to parse JsonDocument","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs","lineNumber":27,"sourceCode":"using Elsa.Common.Serialization;\n\nnamespace Elsa.Workflows.Activities.Flowchart.Serialization;\n\n/// <summary>\n/// A JSON converter for <see cref=\"Activities.Flowchart\"/>.\n/// </summary>\n[UsedImplicitly]\npublic class FlowchartJsonConverter(IIdentityGenerator identityGenerator, ISerializationTypeRegistry workflowJsonTypeRegistry, ILoggerFactory loggerFactory) : JsonConverter<Activities.Flowchart>\n{\n    private const string AllActivitiesKey = \"allActivities\";\n    private const string AllConnectionsKey = \"allConnections\";\n    private const string NotFoundConnectionsKey = \"notFoundConnections\";\n\n    /// <inheritdoc />\n    public override Activities.Flowchart Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (!JsonDocument.TryParseValue(ref reader, out var doc))\n            throw new JsonException(\"Failed to parse JsonDocument\");\n\n        var id = doc.RootElement.TryGetProperty(\"id\", out var idAttribute) ? idAttribute.GetString()! : identityGenerator.GenerateId();\n        var nodeId = doc.RootElement.TryGetProperty(\"nodeId\", out var nodeIdAttribute) ? nodeIdAttribute.GetString() : null;\n        var name = doc.RootElement.TryGetProperty(\"name\", out var nameElement) ? nameElement.GetString() : null;\n        var type = doc.RootElement.TryGetProperty(\"type\", out var typeElement) ? typeElement.GetString() : null;\n        var version = doc.RootElement.TryGetProperty(\"version\", out var versionElement) ? versionElement.GetInt32() : 1;\n        var runAsynchronously = doc.RootElement.TryGetProperty(\"runAsynchronously\", out var runAsyncElement) && runAsyncElement.GetBoolean();\n\n        var connectionsElement = doc.RootElement.TryGetProperty(\"connections\", out var connectionsEl) ? connectionsEl : default;\n        var activitiesElement = doc.RootElement.TryGetProperty(\"activities\", out var activitiesEl) ? activitiesEl : default;\n        var activities = activitiesElement.ValueKind != JsonValueKind.Undefined ? activitiesElement.Deserialize<ICollection<IActivity>>(options) ?? new List<IActivity>() : new List<IActivity>();\n        var activityDictionary = activities.ToDictionary(x => x.Id);\n        var connections = DeserializeConnections(connectionsElement, activityDictionary, options);\n        var notFoundConnections = GetNotFoundConnections(doc.RootElement, activityDictionary, connections, options);\n        var connectionsToRestore = FindConnectionsThatCanBeRestored(notFoundConnections, activities);\n        var connectionComparer = new ConnectionComparer();\n        var connectionsWithRestoredOnes = connections.Except(notFoundConnections, connectionComparer).Union(connectionsToRestore, connectionComparer).ToList();\n","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Serialization/FlowchartJsonConverter.cs#L9-L45","documentation":"Thrown in FlowchartJsonConverter.Read when the JSON token for a Flowchart activity cannot be parsed into a JsonDocument. This guards against malformed JSON before reading id, nodeId, name, type, version, and connections properties during workflow definition deserialization.","triggerScenarios":"Deserializing a workflow definition where the flowchart node's JSON is syntactically invalid — truncated JSON, wrong token type (string/number instead of object), or encoding corruption.","commonSituations":"Corrupted stored workflow definitions; truncated HTTP request bodies; hand-edited JSON with syntax errors; systems that re-encode the payload incorrectly during round-trips.","solutions":["Parse and validate the definition JSON independently (JsonDocument.Parse) to pinpoint the malformed fragment.","Check storage/transport layers for truncation or encoding issues (column length limits, charset mismatches).","Ensure the flowchart is serialized as a JSON object, not wrapped in a string.","Catch JsonException around deserialization and include the failing JSON snippet in diagnostics."],"exampleFix":"// before\nvar flowchart = JsonSerializer.Deserialize<Activities.Flowchart>(json); // throws on malformed json\n// after\nusing var doc = JsonDocument.Parse(json); // validate first\nvar flowchart = json.Deserialize<Activities.Flowchart>();","handlingStrategy":"try-catch","validationCode":"using var doc = JsonDocument.Parse(definitionJson); // pre-validate whole definition","typeGuard":"static bool IsJsonObjectToken(string json) { try { using var d = JsonDocument.Parse(json); return d.RootElement.ValueKind == JsonValueKind.Object; } catch (JsonException) { return false; } }","tryCatchPattern":"try { var flowchart = JsonSerializer.Deserialize<Activities.Flowchart>(json); }\ncatch (JsonException ex)\n{\n    logger.LogError(ex, \"Malformed flowchart JSON: {Message}\", ex.Message);\n    throw new WorkflowDefinitionFormatException(\"Definition contains invalid flowchart JSON\", ex);\n}","preventionTips":["Round-trip test definition serialization/deserialization in CI.","Ensure transports do not truncate payloads (check body size limits, column sizes).","Never wrap activity JSON in an extra string layer."],"tags":["json","serialization","flowchart","deserialization"],"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"}