{"record":{"id":"d1bdfd9653356fb4","repo":"elsa-workflows/elsa-core","slug":"workflow-json-type-alias-resolved-to-non-instantiable-type","errorCode":null,"errorMessage":"Workflow JSON type alias resolved to non-instantiable type '{targetType}'.","messagePattern":"Workflow JSON type alias resolved to non-instantiable type '(.+?)'\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs","lineNumber":406,"sourceCode":"            \"Value of type {PayloadType} has no registered serialization alias, so it is stored without a type discriminator and will be read back as a property bag with camel-cased keys instead of as {PayloadType}. \" +\n            \"Register it during startup with AddTypeAlias<{PayloadTypeName}>(), or use a Dictionary<string, object> if a property bag is what you intend.\",\n            type,\n            type,\n            type.Name);\n    }\n\n    private static Type GetInstantiableTargetType(Type targetType)\n    {\n        if (targetType.ContainsGenericParameters)\n            throw new JsonException($\"Workflow JSON type alias resolved to open generic type '{targetType}'.\");\n\n        if (!targetType.IsInterface && !targetType.IsAbstract)\n            return targetType;\n\n        if (SerializationTypeResolver.TryGetInstantiableCollectionType(targetType, out var instantiableCollectionType))\n            return instantiableCollectionType;\n\n        throw new JsonException($\"Workflow JSON type alias resolved to non-instantiable type '{targetType}'.\");\n    }\n\n    private static object ReadPrimitive(ref Utf8JsonReader reader, JsonSerializerOptions options)\n    {\n        return (reader.TokenType switch\n        {\n            JsonTokenType.True => true,\n            JsonTokenType.False => false,\n            JsonTokenType.Number when reader.TryGetInt64(out var l) => l,\n            JsonTokenType.Number => reader.GetDouble(),\n            JsonTokenType.String => reader.GetString(),\n            JsonTokenType.Null => null,\n            _ => throw new JsonException(\"Not a primitive type.\")\n        })!;\n    }\n\n    private object ReadObject(ref Utf8JsonReader reader, JsonSerializerOptions options)\n    {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs#L388-L424","documentation":"Thrown by PolymorphicObjectConverter.GetInstantiableTargetType when a JSON type alias resolves to a target type that is neither concrete nor has a known instantiable collection substitute. Interfaces and abstract classes cannot be instantiated with 'new', so the serializer refuses instead of producing an invalid object. It indicates the type alias or $type in the workflow JSON points at a type the resolver cannot materialize.","triggerScenarios":"Deserializing workflow JSON whose $type/type alias resolves to an interface (e.g. an interface-typed property without a concrete alias mapping) or an abstract class, and the type is not registered in the type resolver nor mapped by SerializationTypeResolver.TryGetInstantiableCollectionType (e.g. IEnumerable<T>).","commonSituations":"Custom activities with properties typed as interfaces or abstract classes where the concrete implementation was never registered via ITypeAliasRegistry or AddActivationConstructorBody; renamed/refactored types so the alias now maps to an abstract base; custom SerializationTypeResolver missing a collection instantiation mapping.","solutions":["Register a concrete type for the alias/interface via the type resolver or type-alias registration so GetInstantiableTargetType returns an instantiable type","Change the workflow/activity property to a concrete, instantiable type instead of an interface or abstract class","If the target is a collection interface, ensure TryGetInstantiableCollectionType can map it (e.g. IEnumerable<T> -> List<T>) or add a custom mapping","Update stale $type values in the stored workflow JSON after type renames"],"exampleFix":"// before\npublic IMyHandler Handler { get; set; }\n// after\nservices.AddTypeAlias<IMyHandler, MyHandler>(); // register concrete instantiable type\n// or\npublic MyHandler Handler { get; set; }","handlingStrategy":"validation","validationCode":"var targetType = ResolveAlias(alias); // your alias resolution\nif (targetType.IsInterface || targetType.IsAbstract)\n    throw new InvalidOperationException($\"Alias '{alias}' must map to a concrete type; register one in the type resolver.\");","typeGuard":"static bool IsInstantiable(Type t) => !t.IsInterface && !t.IsAbstract;","tryCatchPattern":null,"preventionTips":["Register concrete implementations for every interface/abstract type used in activity properties","Keep $type aliases in workflow JSON in sync after refactors; validate stored definitions after renames","Add a startup smoke test that deserializes representative workflow definitions"],"tags":["json","deserialization","workflow","type-resolution"],"backgroundTag":"class-not-found","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}