elsa-workflows/elsa-core · error · InvalidOperationException

Type does not expose an Add method for .

Error message

Type {collectionType} does not expose an Add method for {desiredCollectionItemType}.

What it means

When ConvertTo converts an enumerable to a set- or collection-typed target, it instantiates a HashSet<> or List<> of the desired item type and reflects for an Add method with the exact item parameter type. If the constructed collection type lacks such an Add method it throws InvalidOperationException — effectively an internal invariant violation.

Solutions

  1. Inspect how desiredCollectionItemType/desiredSetType are derived and ensure the target type is a closed generic collection (e.g. ISet<int>, not ISet<> or a custom set type)
  2. Convert to a concrete collection type (List<T>/HashSet<T>) instead of a custom set interface in the target property
  3. Catch InvalidOperationException in ConvertTo callers (or file a bug with the exact target type) since this indicates an unsupported conversion path

Example fix

// before
public ISet<MyItem> Items { get; set; }
// after (use a concrete closed generic)
public HashSet<MyItem> Items { get; set; }
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure closed generic collection types
if (targetType.IsGenericType && targetType.GetGenericArguments().Length != targetType.GetGenericArguments().Length)
    throw new InvalidOperationException("Use closed generic collections");

Try / catch

try { collection = ObjectConverter.ConvertTo(source, collectionType); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Add method")) { collection = default; }

Prevention

When it happens

Trigger: Converting an enumerable into ICollection<T>/ISet<T>-like targets where Activator-created HashSet<T>/List<T> does not expose Add(T) — practically a bug or unusual generic configuration (e.g. desiredCollectionItemType resolved incorrectly).

Common situations: Rare; encountered after upgrades or when the desired collection item type derivation changes (e.g. generic type resolution against custom set interfaces).

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/0d8086650387ae93. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs:278

                    s
                };
        }

        if (value is IEnumerable enumerable)
        {
            if (underlyingTargetType is { IsGenericType: true })
            {
                var desiredCollectionItemType = targetType.GenericTypeArguments[0];
                var desiredCollectionType = typeof(ICollection<>).MakeGenericType(desiredCollectionItemType);
                var desiredSetType = typeof(ISet<>).MakeGenericType(desiredCollectionItemType);

                if (underlyingTargetType.IsAssignableFrom(desiredCollectionType) || desiredCollectionType.IsAssignableFrom(underlyingTargetType))
                {
                    var collectionType = desiredSetType.IsAssignableFrom(underlyingTargetType)
                        ? typeof(HashSet<>).MakeGenericType(desiredCollectionItemType)
                        : typeof(List<>).MakeGenericType(desiredCollectionItemType);
                    var collection = Activator.CreateInstance(collectionType)!;
                    var addMethod = collectionType.GetMethod("Add", [desiredCollectionItemType]) ?? throw new InvalidOperationException($"Type {collectionType} does not expose an Add method for {desiredCollectionItemType}.");

                    foreach (var item in enumerable)
                    {
                        var convertedItem = ConvertTo(item, desiredCollectionItemType);
                        addMethod.Invoke(collection, [convertedItem]);
                    }

                    return collection;
                }
            }

            if (underlyingTargetType.IsArray)
            {
                var executedEnumerable = enumerable.Cast<object>().ToList();
                var underlyingTargetElementType = underlyingTargetType.GetElementType()!;
                var array = Array.CreateInstance(underlyingTargetElementType, executedEnumerable.Count);
                var index = 0;
                foreach (var item in executedEnumerable)

View on GitHub (pinned to fe9217bdfa)