elsa-workflows/elsa-core · error · JsonException
Expected start of object.
Error message
Expected start of object.
What it means
PolymorphicDictionaryConverter.Read deserializes JSON objects into IDictionary<string,object> with polymorphic values. It requires the current token to be JsonTokenType.StartObject; otherwise it throws JsonException("Expected start of object."). This guards the contract that dictionary targets must map to JSON objects.
Solutions
- Fix the JSON payload so the dictionary field is a JSON object (key/value pairs).
- Change the property type to match the actual payload shape if arrays are legitimate.
- Validate the payload shape before deserialization.
- Migrate legacy stored state data to the object shape expected by the current model.
Example fix
// before
var d = JsonSerializer.Deserialize<IDictionary<string, object>>("[1,2,3]");
// after
var d = JsonSerializer.Deserialize<IDictionary<string, object>>("{\"a\":1}"); Defensive patterns
Strategy: validation
Validate before calling
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.ValueKind != JsonValueKind.Object)
throw new InvalidOperationException("Expected a JSON object for dictionary deserialization"); Type guard
static bool IsJsonObjectString(string s) { try { using var d = JsonDocument.Parse(s); return d.RootElement.ValueKind == JsonValueKind.Object; } catch { return false; } } Try / catch
try { var d = JsonSerializer.Deserialize<IDictionary<string, object>>(json); } catch (JsonException ex) when (ex.Message == "Expected start of object.") { log.LogError(ex, "Dictionary payload is not a JSON object"); } Prevention
- Ensure dictionary-typed fields are always serialized as JSON objects
- Migrate legacy array-shaped state data before upgrading
- Validate request payloads at the API boundary before deserializing into dictionaries
When it happens
Trigger: Deserializing a field declared as IDictionary<string,object> (or a dictionary-like property) whose JSON value is an array, string, number, or null instead of an object (src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs:25).
Common situations: Workflow state where a dictionary property was previously stored as a JSON array and the model changed; hand-written JSON for variables/settings using wrong shape; API clients posting arrays where objects are expected.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Runtime entity definition document
- Runtime entity instance document
- Failed to parse JsonDocument
- Failed to extract activity type property
- Unknown token
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/c89508235475c4ca.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicDictionaryConverter.cs:25
/// <summary>
/// A converter that can convert a dictionary of string keys and object values while preserving the object type.
/// </summary>
public class PolymorphicDictionaryConverter : JsonConverter<IDictionary<string, object>>
{
private readonly JsonConverter<object> _objectConverter;
/// <inheritdoc />
public PolymorphicDictionaryConverter(JsonSerializerOptions options, ISerializationTypeRegistry workflowJsonTypeRegistry)
{
var factory = (JsonConverterFactory)(options.Converters.FirstOrDefault(x => x is PolymorphicObjectConverterFactory) ?? new PolymorphicObjectConverterFactory(workflowJsonTypeRegistry));
_objectConverter = (JsonConverter<object>)factory.CreateConverter(typeof(object), options)!;
}
/// <inheritdoc />
public override IDictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException("Expected start of object.");
var dictionary = new Dictionary<string, object>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
return dictionary;
var key = reader.GetString()!;
reader.Read();
var value = _objectConverter.Read(ref reader, typeof(object), options)!;
dictionary.Add(key, value);
}
throw new JsonException("Expected end of object.");
}
/// <inheritdoc />View on GitHub (pinned to fe9217bdfa)