elsa-workflows/elsa-core · error · InvalidOperationException
Output converter ID ' ' is registered more than once or…
Error message
Output converter ID '{duplicate.Key}' is registered more than once or differs from another registration only by case. What it means
Thrown by OutputConverterRegistry.ValidateRegistrations when two or more output converter registrations share the same descriptor Id, including IDs that differ only by letter case (grouped with OrdinalIgnoreCase). Converter IDs must be unique case-insensitively so registry lookups are unambiguous.
Solutions
- Give each converter a unique Id, e.g. namespace-qualified like 'MyCompany.IntToString'.
- Remove duplicate registrations (check whether the module/feature is being added twice).
- Audit installed packages for converters using the same Id and prefer one, overriding the other intentionally.
Example fix
// before descriptor.Id = "int-to-string"; // in ModuleA descriptor.Id = "Int-To-String"; // in ModuleB // after descriptor.Id = "ModuleA.IntToString"; descriptor.Id = "ModuleB.IntToString";
Defensive patterns
Strategy: validation
Validate before calling
var ids = registrations.Select(r => r.Descriptor.Id).ToList();
var dupes = ids.GroupBy(i => i, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
if (dupes.Any()) throw new InvalidOperationException($"Duplicate converter Ids: {string.Join(", ", dupes)}"); Try / catch
try
{
host = builder.Build(); // registry validated during startup
}
catch (InvalidOperationException ex) when (ex.Message.Contains("registered more than once"))
{
logger.LogCritical(ex, "Duplicate output converter Ids detected; check installed modules");
throw;
} Prevention
- Namespace-qualify converter Ids (e.g., 'Company.Module.ConverterName') to guarantee uniqueness across packages.
- Avoid registering the same feature/module twice.
- Keep a central registry of converter Ids in your solution.
When it happens
Trigger: Registering two OutputConverterDescriptors with the same Id (e.g., 'int-to-string' registered twice, or 'IntToString' and 'inttostring' in different modules), often when a module is added twice or two packages define overlapping converters.
Common situations: Loading two versions of a plugin assembly, duplicating a feature's DI registrations, and two teams independently picking the same converter Id.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Output converter IDs cannot be empty.
- Output converter registration
- Duplicate ingress source registration for name
- OpenTelemetry gRPC ingestion is enabled, but no gRPC…
- Output converter ' ' failed during for output ' ' of…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/db71af87c5974d81.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Services/OutputConverterRegistry.cs:61
}
private static void ValidateRegistrations(IReadOnlyCollection<OutputConverterRegistration> registrations)
{
foreach (var registration in registrations)
{
ValidateDescriptor(registration.Descriptor);
var id = registration.Descriptor.Id;
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)