elsa-workflows/elsa-core · error · InvalidOperationException

Output converter ' ' cannot use open-generic source or…

Error message

Output converter '{descriptor.Id}' cannot use open-generic source or result types.

What it means

Thrown by OutputConverterRegistry.ValidateDescriptor when a converter's SourceType or ResultType contains open generic parameters (e.g., typeof(IEnumerable<>)). The runtime must match concrete runtime value types against the descriptor, so open generics cannot be resolved or dispatched.

Solutions

  1. Close the generic types: use typeof(IEnumerable<int>) or the concrete closed type instead of typeof(IEnumerable<>).
  2. Call MakeGenericType(concreteArgs) on the open type when constructing the descriptor at registration time.
  3. Register one descriptor per concrete type combination you need to support.

Example fix

// before
descriptor.SourceType = typeof(IEnumerable<>);

// after
descriptor.SourceType = typeof(IEnumerable<int>);
// or, dynamically:
descriptor.SourceType = typeof(IEnumerable<>).MakeGenericType(elementType);
Defensive patterns

Strategy: validation

Validate before calling

if (descriptor.SourceType.ContainsGenericParameters || descriptor.ResultType.ContainsGenericParameters)
    throw new InvalidOperationException("Converter types must be closed (call MakeGenericType before registering).");

Type guard

bool UsesClosedTypes(OutputConverterDescriptor d) => !d.SourceType.ContainsGenericParameters && !d.ResultType.ContainsGenericParameters;

Try / catch

try
{
    services.AddOutputConverter(descriptor);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("open-generic"))
{
    logger.LogCritical(ex, "Converter {Id} uses open generics; register closed types instead", descriptor.Id);
    throw;
}

Prevention

When it happens

Trigger: Registering a converter with SourceType = typeof(T) / typeof(List<>) or a ResultType that is a generic type definition, typically when writing a generic converter class and copying its generic type parameters into the descriptor.

Common situations: Authors wanting 'convert anything to string' converters using generic parameters, converters ported from open-generic classes, and reflection-built descriptors where MakeGenericType was never called.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/ab72d378f109996f. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Workflows.Core/Services/OutputConverterRegistry.cs:70

            if (!string.Equals(id, registration.ServiceKey, StringComparison.Ordinal))
                throw new InvalidOperationException($"Output converter registration '{id}' must use the Converter ID as its service key.");
        }

        var duplicate = registrations
            .GroupBy(x => x.Descriptor.Id, StringComparer.OrdinalIgnoreCase)
            .FirstOrDefault(x => x.Count() > 1);

        if (duplicate != null)
            throw new InvalidOperationException($"Output converter ID '{duplicate.Key}' is registered more than once or differs from another registration only by case.");
    }

    internal static void ValidateDescriptor(OutputConverterDescriptor descriptor)
    {
        if (string.IsNullOrWhiteSpace(descriptor.Id))
            throw new InvalidOperationException("Output converter IDs cannot be empty.");

        if (descriptor.SourceType.ContainsGenericParameters || descriptor.ResultType.ContainsGenericParameters)
            throw new InvalidOperationException($"Output converter '{descriptor.Id}' cannot use open-generic source or result types.");
    }
}

View on GitHub (pinned to fe9217bdfa)