{"record":{"id":"2b2021f69bf22fcb","repo":"elsa-workflows/elsa-core","slug":"output-converter-ids-cannot-be-empty","errorCode":null,"errorMessage":"Output converter IDs cannot be empty.","messagePattern":"Output converter IDs cannot be empty\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Core/Extensions/OutputConverterServiceCollectionExtensions.cs","lineNumber":42,"sourceCode":"\n        OutputConverterRegistry.ValidateDescriptor(descriptor);\n        ValidateUniqueId(services, descriptor.Id);\n\n        var registration = new OutputConverterRegistration(descriptor, descriptor.Id, serviceLifetime);\n        services.AddSingleton(registration);\n        services.Add(ServiceDescriptor.DescribeKeyed(\n            typeof(IOutputConverter),\n            descriptor.Id,\n            typeof(TConverter),\n            serviceLifetime));\n        services.TryAddSingleton<IOutputConverterRegistry, OutputConverterRegistry>();\n        return services;\n    }\n\n    private static void ValidateUniqueId(IServiceCollection services, string id)\n    {\n        if (string.IsNullOrWhiteSpace(id))\n            throw new ArgumentException(\"Output converter IDs cannot be empty.\", nameof(id));\n\n        var existingRegistration = services\n            .Where(x => x.ServiceType == typeof(OutputConverterRegistration))\n            .Select(x => x.ImplementationInstance)\n            .OfType<OutputConverterRegistration>()\n            .FirstOrDefault(x => string.Equals(x.Descriptor.Id, id, StringComparison.OrdinalIgnoreCase));\n\n        if (existingRegistration != null)\n            throw new InvalidOperationException($\"Output converter ID '{id}' is already registered or differs from '{existingRegistration.Descriptor.Id}' only by case.\");\n    }\n}\n","sourceCodeStart":24,"sourceCodeEnd":54,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Extensions/OutputConverterServiceCollectionExtensions.cs#L24-L54","documentation":"AddOutputConverter registers an output converter with an ID; ValidateUniqueId rejects empty/whitespace IDs with ArgumentException before any duplicate check. This keeps converter IDs stable and valid for lookup. It is a guard against misconfigured registrations.","triggerScenarios":"Calling services.AddOutputConverter(new OutputConverterDescriptor { Id = \"\" }) or AddOutputConverter(id: \"  \", ...) with a null, empty, or whitespace-only ID string.","commonSituations":"Building the descriptor from config where the ID key is missing; string interpolation producing an empty value; copy-pasting a registration template without filling in the ID.","solutions":["Pass a non-empty, meaningful converter ID string","If the ID comes from configuration, fail fast with a clear config error instead of registering","Guard with string.IsNullOrWhiteSpace before calling AddOutputConverter"],"exampleFix":"// before\nservices.AddOutputConverter(new OutputConverterDescriptor { Id = config[\"Converter:Id\"]! });\n// after\nvar id = config[\"Converter:Id\"];\nif (string.IsNullOrWhiteSpace(id)) throw new InvalidOperationException(\"Output converter id must be configured.\");\nservices.AddOutputConverter(new OutputConverterDescriptor { Id = id });","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException(\"Converter id must be non-empty.\", nameof(id));","typeGuard":null,"tryCatchPattern":"try { services.AddOutputConverter(descriptor); } catch (ArgumentException ex) when (ex.ParamName == \"id\") { logger.LogError(ex, \"Invalid output converter id\"); }","preventionTips":["Never build IDs from possibly-empty config values without checking","Centralize converter registration so IDs are reviewed in one place"],"tags":["dependency-injection","configuration","argument"],"backgroundTag":"empty-required-field","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}