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

  1. Use a generic collection type (List<T>, Collection<T>, T[]) for the target property.
  2. If a custom collection is required, derive from Collection<T> or List<T> so the element type is discoverable.
  3. Add a custom JsonConverter for the exotic collection type instead of relying on polymorphic inference.
  4. 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

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


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)