From 4cd2c4cda6e2d646336656a4707f3bb570833057 Mon Sep 17 00:00:00 2001 From: j03y-nxxbz Date: Tue, 20 Jan 2026 13:27:55 +0100 Subject: [PATCH 1/4] Bugfix: error thrown in ReadSyntheticInputs Direct cause: typeName was missing in synthetic input property Root cause: worklfow used as activity defined input with reserved name 'Metadata' Why fix was needed? Because the uncaught exception was preventing other workflows from being published. Even though this exception occurs, it should not prevent publishing other workflows. Solution introduced here: - Collect exceptions that prevent an activity from being in the expected state. In this case, we expected all syntehtic input properties to be valid, but they are not. - Return the list of exceptions to the caller, along with an IActivity instance that does not throw exceptions - The caller, in this case ActivityJsonConverter, can log any exceptions, whilst not breaking the loop with uncaught exceptions. --- .../Compiler/ElsaScriptCompiler.cs | 5 +-- .../Contracts/IActivityFactory.cs | 4 +-- ...InvalidActivityDescriptorInputException.cs | 5 +++ .../Models/ActivityConstructionResult.cs | 17 ++++++++++ .../Models/ActivityConstructorContext.cs | 31 +++++++++++++------ .../Models/ActivityDescriptor.cs | 2 +- .../Converters/ActivityJsonConverter.cs | 22 +++++++++++-- .../Services/ActivityDescriber.cs | 6 ++-- .../Services/ActivityFactory.cs | 2 +- ...flowDefinitionActivityDescriptorFactory.cs | 5 +-- .../Services/HostMethodActivityDescriber.cs | 5 +-- ...onActivityConstructorContextHelperTests.cs | 21 +++++++------ .../Converters/ActivityJsonConverterTests.cs | 11 +++++-- 13 files changed, 98 insertions(+), 38 deletions(-) create mode 100644 src/modules/Elsa.Workflows.Core/Exceptions/InvalidActivityDescriptorInputException.cs create mode 100644 src/modules/Elsa.Workflows.Core/Models/ActivityConstructionResult.cs diff --git a/src/modules/Elsa.Dsl.ElsaScript/Compiler/ElsaScriptCompiler.cs b/src/modules/Elsa.Dsl.ElsaScript/Compiler/ElsaScriptCompiler.cs index 8cb52e32f..65a53fb89 100644 --- a/src/modules/Elsa.Dsl.ElsaScript/Compiler/ElsaScriptCompiler.cs +++ b/src/modules/Elsa.Dsl.ElsaScript/Compiler/ElsaScriptCompiler.cs @@ -202,8 +202,9 @@ public class ElsaScriptCompiler(IActivityRegistryLookupService activityRegistryL else { // No positional arguments, use default constructor - var activityConstructorContext = new ActivityConstructorContext(activityDescriptor, ActivityActivator.Create); - activity = activityDescriptor.Constructor(activityConstructorContext); + var activityConstructorContext = new ActivityConstructorContext(activityDescriptor, (t) => new(ActivityActivator.Create(t))); + var activityConstructionResult = activityDescriptor.Constructor(activityConstructorContext); + activity = activityConstructionResult.Activity; } // Set named argument properties diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs index cb41ef2de..4c3459b77 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs @@ -6,14 +6,14 @@ namespace Elsa.Workflows; public interface IActivityFactory { [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] - IActivity Create(Type type, ActivityConstructorContext context); + ActivityConstructionResult Create(Type type, ActivityConstructorContext context); } [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] public static class ActivityFactoryExtensions { [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] - public static IActivity CreateActivity(this IActivityFactory factory, ActivityConstructorContext context) + public static ActivityConstructionResult CreateActivity(this IActivityFactory factory, ActivityConstructorContext context) { return factory.Create(typeof(T), context); } diff --git a/src/modules/Elsa.Workflows.Core/Exceptions/InvalidActivityDescriptorInputException.cs b/src/modules/Elsa.Workflows.Core/Exceptions/InvalidActivityDescriptorInputException.cs new file mode 100644 index 000000000..ddccd3787 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Exceptions/InvalidActivityDescriptorInputException.cs @@ -0,0 +1,5 @@ +namespace Elsa.Workflows.Exceptions; + +public sealed class InvalidActivityDescriptorInputException(string message) : Exception(message) +{ +} diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityConstructionResult.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructionResult.cs new file mode 100644 index 000000000..b90e64f22 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructionResult.cs @@ -0,0 +1,17 @@ +namespace Elsa.Workflows.Models; + +public class ActivityConstructionResult(IActivity activity, IEnumerable? exceptions = null) +{ + public bool HasExceptions => Exceptions.Any(); + + public IActivity Activity { get; } = activity; + public IEnumerable Exceptions { get; } = exceptions ?? []; + + public ActivityConstructionResult Cast() where TActivity : IActivity => new ((TActivity)Activity, Exceptions); +} + +public sealed class ActivityConstructionResult(TActivity activity, IEnumerable? exceptions = null) : ActivityConstructionResult(activity, exceptions) + where TActivity : IActivity +{ + public new TActivity Activity { get; } = activity; +} diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs index 38f35415b..6293a3d75 100644 --- a/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs +++ b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs @@ -3,15 +3,17 @@ using System.Text.Json.Nodes; using Elsa.Expressions.Helpers; using Elsa.Extensions; using Elsa.Workflows.Attributes; +using Elsa.Workflows.Exceptions; using Elsa.Workflows.Memory; using Humanizer; +using Microsoft.Extensions.Logging; namespace Elsa.Workflows.Models; -public record ActivityConstructorContext(ActivityDescriptor ActivityDescriptor, Func ActivityFactory) +public record ActivityConstructorContext(ActivityDescriptor ActivityDescriptor, Func ActivityFactory) { - public T CreateActivity() where T : IActivity => (T)ActivityFactory(typeof(T)); - public IActivity CreateActivity(Type type) => ActivityFactory(type); + public ActivityConstructionResult CreateActivity() where T : IActivity => ActivityFactory(typeof(T)).Cast(); + public ActivityConstructionResult CreateActivity(Type type) => ActivityFactory(type); } public static class JsonActivityConstructorContextHelper @@ -21,13 +23,15 @@ public static class JsonActivityConstructorContextHelper return new ActivityConstructorContext(activityDescriptor, type => CreateActivity(activityDescriptor, type, element, serializerOptions)); } - public static T CreateActivity(ActivityDescriptor activityDescriptor, JsonElement element, JsonSerializerOptions serializerOptions) where T : IActivity + public static ActivityConstructionResult CreateActivity(ActivityDescriptor activityDescriptor, JsonElement element, JsonSerializerOptions serializerOptions) where T : IActivity { - return (T)CreateActivity(activityDescriptor, typeof(T), element, serializerOptions); + return CreateActivity(activityDescriptor, typeof(T), element, serializerOptions).Cast(); } - public static IActivity CreateActivity(ActivityDescriptor activityDescriptor, Type type, JsonElement element, JsonSerializerOptions serializerOptions) + public static ActivityConstructionResult CreateActivity(ActivityDescriptor activityDescriptor, Type type, JsonElement element, JsonSerializerOptions serializerOptions) { + var exceptions = new List(); + // 1) Grab the raw text var raw = element.GetRawText(); @@ -56,14 +60,14 @@ public static class JsonActivityConstructorContextHelper composite.Setup(); // 9) Existing synthetic inputs/outputs routines, using the cleanedElement - ReadSyntheticInputs(activityDescriptor, activity, cleanedElement, serializerOptions); + ReadSyntheticInputs(activityDescriptor, activity, cleanedElement, serializerOptions, exceptions); ReadSyntheticOutputs(activityDescriptor, activity, cleanedElement); // 10) Finally re‑apply those flags activity.SetCanStartWorkflow(canStartWorkflow); activity.SetRunAsynchronously(runAsynchronously); - return activity; + return new(activity, exceptions); } /// @@ -140,7 +144,7 @@ public static class JsonActivityConstructorContextHelper } } - private static void ReadSyntheticInputs(ActivityDescriptor activityDescriptor, IActivity activity, JsonElement activityRoot, JsonSerializerOptions options) + private static void ReadSyntheticInputs(ActivityDescriptor activityDescriptor, IActivity activity, JsonElement activityRoot, JsonSerializerOptions options, List exceptions) { foreach (var inputDescriptor in activityDescriptor.Inputs.Where(x => x.IsSynthetic)) { @@ -152,6 +156,15 @@ public static class JsonActivityConstructorContextHelper if (!activityRoot.TryGetProperty(propertyName, out var propertyElement) || propertyElement.ValueKind == JsonValueKind.Null || propertyElement.ValueKind == JsonValueKind.Undefined) continue; + if(propertyElement.ValueKind == JsonValueKind.Object && !propertyElement.TryGetProperty("typeName", out var typeNameElement)) + { + var exception = new InvalidActivityDescriptorInputException( + $"Activity descriptor '{activityDescriptor.Name}' has invalid input property '{propertyName}'; missing required property 'typeName'" + ); + exceptions.Add(exception); + continue; + } + var isWrapped = propertyElement.ValueKind == JsonValueKind.Object && propertyElement.GetProperty("typeName").ValueKind != JsonValueKind.Undefined; if (isWrapped) diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs index 8b6cf8675..950566795 100644 --- a/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs +++ b/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs @@ -69,7 +69,7 @@ public class ActivityDescriptor /// Instantiates a concrete instance of an . /// [JsonIgnore] - public Func Constructor { get; set; } = null!; + public Func Constructor { get; set; } = null!; /// /// The kind of activity. diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs index a07f8268e..dc86b6fd4 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs @@ -7,6 +7,7 @@ using Elsa.Workflows.Helpers; using Elsa.Workflows.Models; using Elsa.Workflows.Serialization.Helpers; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Elsa.Workflows.Serialization.Converters; @@ -38,13 +39,16 @@ public class ActivityJsonConverter( } var clonedOptions = GetClonedOptions(options); + var logger = serviceProvider.GetRequiredService>(); // If the activity type is not found, create a NotFoundActivity instead. if (activityDescriptor == null) { var notFoundActivityDescriptor = activityRegistry.Find()!; - var notFoundActivity = JsonActivityConstructorContextHelper.CreateActivity(notFoundActivityDescriptor, activityRoot, clonedOptions); + var notFoundActivityResult = JsonActivityConstructorContextHelper.CreateActivity(notFoundActivityDescriptor, activityRoot, clonedOptions); + LogExceptionsIfAny(notFoundActivityResult); + var notFoundActivity = notFoundActivityResult.Activity; notFoundActivity.Type = notFoundActivityTypeName; notFoundActivity.Version = 1; notFoundActivity.MissingTypeName = activityTypeName; @@ -56,8 +60,20 @@ public class ActivityJsonConverter( } var context = JsonActivityConstructorContextHelper.Create(activityDescriptor, activityRoot, clonedOptions); - var activity = activityDescriptor.Constructor(context); - return activity; + var activityResult = activityDescriptor.Constructor(context); + LogExceptionsIfAny(activityResult); + + return activityResult.Activity; + } + + void LogExceptionsIfAny(ActivityConstructionResult result) + { + if (!result.HasExceptions) + return; + + var logger = serviceProvider.GetRequiredService>(); + foreach (var exception in result.Exceptions) + logger.LogWarning("An exception was thrown while constructing activity with id '{activityId}': {Message}", result.Activity.Id, exception.Message); } /// diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs index 2fd774cca..8498bc4eb 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs @@ -92,9 +92,9 @@ public class ActivityDescriber(IPropertyDefaultValueResolver defaultValueResolve }, Constructor = context => { - var activity = context.CreateActivity(activityType); - activity.Type = fullTypeName; - return activity; + var activityResult = context.CreateActivity(activityType); + activityResult.Activity.Type = fullTypeName; + return activityResult; }, }; diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs index f4cf6a097..3b29b0541 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs @@ -6,7 +6,7 @@ namespace Elsa.Workflows; public class ActivityFactory : IActivityFactory { /// - public IActivity Create(Type type, ActivityConstructorContext context) + public ActivityConstructionResult Create(Type type, ActivityConstructorContext context) { return context.CreateActivity(type); } diff --git a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivityDescriptorFactory.cs b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivityDescriptorFactory.cs index be3504c5e..f240d075e 100644 --- a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivityDescriptorFactory.cs +++ b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivityDescriptorFactory.cs @@ -57,7 +57,8 @@ public class WorkflowDefinitionActivityDescriptorFactory }, Constructor = context => { - var activity = context.CreateActivity(); + var activityResult = context.CreateActivity(); + var activity = activityResult.Activity; activity.Type = typeName; activity.WorkflowDefinitionId = definition.DefinitionId; activity.WorkflowDefinitionVersionId = definition.Id; @@ -65,7 +66,7 @@ public class WorkflowDefinitionActivityDescriptorFactory activity.LatestAvailablePublishedVersion = latestPublishedDefinition?.Version ?? definition.Version; activity.LatestAvailablePublishedVersionId = latestPublishedDefinition?.Id ?? definition.Id; - return activity; + return activityResult; } }; } diff --git a/src/modules/Elsa.Workflows.Management/Services/HostMethodActivityDescriber.cs b/src/modules/Elsa.Workflows.Management/Services/HostMethodActivityDescriber.cs index c96db73db..f496e33a3 100644 --- a/src/modules/Elsa.Workflows.Management/Services/HostMethodActivityDescriber.cs +++ b/src/modules/Elsa.Workflows.Management/Services/HostMethodActivityDescriber.cs @@ -57,12 +57,13 @@ public class HostMethodActivityDescriber(IActivityDescriber activityDescriber) : descriptor.Constructor = context => { - var activity = context.CreateActivity(); + var activityResult = context.CreateActivity(); + var activity = activityResult.Activity; activity.Type = activityTypeName; activity.HostType = hostType; activity.MethodName = methodName; activity.RunAsynchronously ??= descriptor.RunAsynchronously; - return activity; + return activityResult; }; descriptor.Inputs.Clear(); diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Models/JsonActivityConstructorContextHelperTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Models/JsonActivityConstructorContextHelperTests.cs index fe9f84b94..fab8da0b6 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Models/JsonActivityConstructorContextHelperTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Models/JsonActivityConstructorContextHelperTests.cs @@ -1,6 +1,7 @@  using System.Text.Json; using System.Text.Json.Serialization; +using Elsa.Workflows.Exceptions; using Elsa.Workflows.Models; namespace Elsa.Workflows.Core.UnitTests.Models; @@ -14,7 +15,7 @@ public sealed class JsonActivityConstructorContextHelperTests [InlineData("Metadata")] [InlineData("_CustomProperties")] [InlineData("CustomProperties")] - public void When_InputName_Is_ReservedKeyWord_Then_ThrowsException_WhenReadingInputs(string reservedInputName) + public void When_InputName_Is_ReservedKeyWord_Then_AddsException_WhenReadingInputs(string reservedInputName) { // Arrange var activityDescriptor = new ActivityDescriptor @@ -31,15 +32,15 @@ public sealed class JsonActivityConstructorContextHelperTests }; var jsonElement = GetJsonElementWithReservedInputName(reservedInputName); - // Act & Assert - Assert.Throws(() => - { - _ = JsonActivityConstructorContextHelper.CreateActivity( - activityDescriptor, - jsonElement, - _serializerOptions - ); - }); + // Act + var result = JsonActivityConstructorContextHelper.CreateActivity( + activityDescriptor, + jsonElement, + _serializerOptions + ); + + // Assert + Assert.Single(result.Exceptions, e => e is InvalidActivityDescriptorInputException); } private static JsonElement GetJsonElementWithReservedInputName(string inputName) diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs index d8969c243..54ce2cd71 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs @@ -125,7 +125,7 @@ public sealed class ActivityJsonConverterTests static IActivityRegistry CreateActivityRegistry(string typeName, IActivity activity, int? version = null) { - var descriptor = new ActivityDescriptor { Constructor = _ => activity }; + var descriptor = new ActivityDescriptor { Constructor = _ => new(activity) }; var activityRegistry = Substitute.For(); if (version.HasValue) @@ -140,7 +140,7 @@ public sealed class ActivityJsonConverterTests { var descriptor = new ActivityDescriptor { - Constructor = _ => WorkflowAsActivity, + Constructor = _ => new(WorkflowAsActivity), CustomProperties = { [customPropertyName] = customPropertyValue } }; @@ -334,6 +334,11 @@ public sealed class ActivityJsonConverterTests private static ActivityJsonConverter CreateSut(IActivityRegistry activityRegistry) { var expressionDescriptorRegistry = new ExpressionDescriptorRegistry([]); + var serviceProvider = Substitute.For(); + serviceProvider + .GetService(typeof(ILogger))! + .Returns(CreateLogger()); + return new( activityRegistry, expressionDescriptorRegistry, @@ -342,7 +347,7 @@ public sealed class ActivityJsonConverterTests new(expressionDescriptorRegistry), CreateLogger() ), - Substitute.For() + serviceProvider ); } From b3d155de63be31e4bca481ed52bd4fc5340e1594 Mon Sep 17 00:00:00 2001 From: j03y-nxxbz Date: Tue, 20 Jan 2026 13:33:47 +0100 Subject: [PATCH 2/4] Actually, I should not have handled obsolete classes/interfaces. Handling that as it should without changing the contract --- src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs | 4 ++-- src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs b/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs index 4c3459b77..cb41ef2de 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IActivityFactory.cs @@ -6,14 +6,14 @@ namespace Elsa.Workflows; public interface IActivityFactory { [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] - ActivityConstructionResult Create(Type type, ActivityConstructorContext context); + IActivity Create(Type type, ActivityConstructorContext context); } [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] public static class ActivityFactoryExtensions { [Obsolete("Use the CreateActivity method on the ActivityConstructorContext context itself")] - public static ActivityConstructionResult CreateActivity(this IActivityFactory factory, ActivityConstructorContext context) + public static IActivity CreateActivity(this IActivityFactory factory, ActivityConstructorContext context) { return factory.Create(typeof(T), context); } diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs index 3b29b0541..bcc81bf92 100644 --- a/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs +++ b/src/modules/Elsa.Workflows.Core/Services/ActivityFactory.cs @@ -6,8 +6,8 @@ namespace Elsa.Workflows; public class ActivityFactory : IActivityFactory { /// - public ActivityConstructionResult Create(Type type, ActivityConstructorContext context) + public IActivity Create(Type type, ActivityConstructorContext context) { - return context.CreateActivity(type); + return context.CreateActivity(type).Activity; } } \ No newline at end of file From a69d44794010239f3c30d1fde3a4fec4501abfe7 Mon Sep 17 00:00:00 2001 From: j03y-nxxbz Date: Tue, 20 Jan 2026 13:36:45 +0100 Subject: [PATCH 3/4] Removing unused variables --- .../Elsa.Workflows.Core/Models/ActivityConstructorContext.cs | 2 +- .../Serialization/Converters/ActivityJsonConverter.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs index 6293a3d75..78d9f1ca3 100644 --- a/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs +++ b/src/modules/Elsa.Workflows.Core/Models/ActivityConstructorContext.cs @@ -156,7 +156,7 @@ public static class JsonActivityConstructorContextHelper if (!activityRoot.TryGetProperty(propertyName, out var propertyElement) || propertyElement.ValueKind == JsonValueKind.Null || propertyElement.ValueKind == JsonValueKind.Undefined) continue; - if(propertyElement.ValueKind == JsonValueKind.Object && !propertyElement.TryGetProperty("typeName", out var typeNameElement)) + if(propertyElement.ValueKind == JsonValueKind.Object && !propertyElement.TryGetProperty("typeName", out var _)) { var exception = new InvalidActivityDescriptorInputException( $"Activity descriptor '{activityDescriptor.Name}' has invalid input property '{propertyName}'; missing required property 'typeName'" diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs index dc86b6fd4..25ef8a252 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs @@ -39,8 +39,7 @@ public class ActivityJsonConverter( } var clonedOptions = GetClonedOptions(options); - var logger = serviceProvider.GetRequiredService>(); - + // If the activity type is not found, create a NotFoundActivity instead. if (activityDescriptor == null) { From b0b2080a35d0aa029798f75c4639989096d18bc7 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 20 Jan 2026 13:50:16 +0100 Subject: [PATCH 4/4] Apply suggestion from @sfmskywalker --- .../Serialization/Converters/ActivityJsonConverter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs index 25ef8a252..125bfe847 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs @@ -39,7 +39,6 @@ public class ActivityJsonConverter( } var clonedOptions = GetClonedOptions(options); - // If the activity type is not found, create a NotFoundActivity instead. if (activityDescriptor == null) {