elsa-workflows/elsa-core · error · InvalidOperationException
Cannot determine the element type of array
Error message
Cannot determine the element type of array '{targetType}'. What it means
PolymorphicObjectConverter.Read, when deserializing a JSON array into a concrete collection type, must determine the element type via generic type arguments. When it cannot (no GenericTypeArguments and no derivable base-type argument), it throws InvalidOperationException. This is an internal invariant failure for exotic collection targets.
Solutions
- Use a generic collection type (List<T>, Collection<T>, T[]) for the target property.
- If a custom collection is required, derive from Collection<T> or List<T> so the element type is discoverable.
- Add a custom JsonConverter for the exotic collection type instead of relying on polymorphic inference.
- Fallback behavior is typeof(object); confirm whether deserializing into List<object> is acceptable.
Example fix
// before
public class MyItems : CollectionBase { ... } // non-generic, element type unknown
// after
public class MyItems : Collection<MyItem> { ... } Defensive patterns
Strategy: type-guard
Validate before calling
var t = typeof(MyCollection);
bool inferable = t.IsGenericType || (t.BaseType?.IsGenericType == true);
if (!inferable) throw new InvalidOperationException($"{t.Name} must be generic so its element type can be inferred"); Type guard
static bool HasInferableElementType(Type t) => t.IsArray || t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
Try / catch
try { var list = JsonSerializer.Deserialize<MyCollection>(json, options); } catch (InvalidOperationException ex) when (ex.Message.Contains("Cannot determine the element type")) { log.LogError(ex, "Make the collection generic"); } Prevention
- Use List<T>, T[], or Collection<T> for collection-typed workflow properties
- Avoid non-generic legacy collection types in models
- Add a serialization round-trip unit test for custom collection classes
When it happens
Trigger: Deserializing a JSON array into a target type whose element type cannot be inferred — e.g. a non-generic collection type deriving from Collection<T>/List<T> chains the converter cannot introspect, or a nested non-generic collection (src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs:139).
Common situations: Custom collection classes without generic parameters; deserializing into MyCollection (non-generic) where Elsa expects T to be discoverable; refactored property types losing their generic argument.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Workflow JSON type alias resolved to open generic type
- Expected end of object.
- Expected start of object.
- Failed to extract activity type property
- Failed to parse JsonDocument
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/ff01a81bf6a8c4f1.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs:139
{
// Remove the _type property name from the JSON, if any.
var parsedNode = JsonNode.Parse(ref reader)!;
if (parsedNode is JsonObject parsedModel) parsedModel.Remove(TypePropertyName);
return parsedNode.Deserialize(targetType, newOptions)!;
}
var isCollection = typeof(ICollection).IsAssignableFrom(targetType);
// Otherwise, deserialize the object as an array.
var elementType = targetType.IsArray
? targetType.GetElementType()
: targetType.GenericTypeArguments.FirstOrDefault() ??
(isCollection // Could be a class derived from Collection<T> or List<T>.
? targetType.BaseType?.GenericTypeArguments[0]
: targetType.GenericTypeArguments.FirstOrDefault()
?? typeof(object));
if (elementType == null)
throw new InvalidOperationException($"Cannot determine the element type of array '{targetType}'.");
var model = JsonElement.ParseValue(ref reader);
var referenceResolver = (newOptions.ReferenceHandler as CrossScopedReferenceHandler)?.GetResolver();
if (model.TryGetProperty(RefPropertyName, out var refProperty))
{
var refId = refProperty.GetString()!;
return referenceResolver?.ResolveReference(refId)!;
}
var values = model.TryGetProperty(ItemsPropertyName, out var itemsProp) ? itemsProp.EnumerateArray().ToList() : model.GetProperty(ValuesPropertyName).EnumerateArray().ToList();
var id = model.TryGetProperty(IdPropertyName, out var idProp) ? idProp.GetString() : default;
var collection = targetType.IsArray ? Array.CreateInstance(elementType, values.Count) : Activator.CreateInstance(targetType)!;
var index = 0;
if (id != null)
referenceResolver?.AddReference(id, collection);
View on GitHub (pinned to fe9217bdfa)