elsa-workflows/elsa-core · error · JsonException
Workflow JSON type alias resolved to open generic type
Error message
Workflow JSON type alias resolved to open generic type '{targetType}'. What it means
PolymorphicObjectConverter.GetInstantiableTargetType maps a JSON type alias to a concrete .NET type for instantiation. If the resolved type still contains open generic parameters (e.g. List<> or a generic interface), it cannot be constructed and this JsonException is thrown. It prevents attempts to create open generic instances.
Solutions
- Ensure the type alias in the JSON resolves to a closed generic (e.g. List`1[[MyNamespace.MyItem, MyAssembly]]).
- Fix custom type-resolver alias registrations to map to closed, instantiable types.
- Use concrete non-generic or closed-generic property types in the model.
- If targeting interfaces, register an instantiable implementation in SerializationTypeResolver.
Example fix
// before (open generic alias) "$type": "System.Collections.Generic.List`1" // after (closed generic) "$type": "System.Collections.Generic.List`1[[Elsa.Workflows.Bookmark, Elsa.Workflows.Core]]"
Defensive patterns
Strategy: validation
Validate before calling
var t = SerializationTypeResolver.Resolve(alias); // or however aliases map
if (t.ContainsGenericParameters) throw new InvalidOperationException($"Type alias '{alias}' maps to open generic {t}"); Type guard
static bool IsInstantiable(Type t) => !t.ContainsGenericParameters && !t.IsAbstract && !t.IsInterface;
Try / catch
try { var obj = JsonSerializer.Deserialize<object>(json, polymorphicOptions); } catch (JsonException ex) when (ex.Message.Contains("open generic type")) { log.LogError(ex, "Fix type alias to a closed generic"); } Prevention
- Register aliases only for closed, instantiable types in your SerializationTypeResolver
- Never hand-write $type/alias values for generic types without full closed-generic names
- Prefer concrete or closed-generic property types in workflow models
When it happens
Trigger: Deserializing JSON with a type alias ($type / type mapping) that resolves to an open generic type such as 'List<>' or 'Dictionary`2' without closed type arguments, via GetInstantiableTargetType during Read (src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs:398).
Common situations: Hand-crafted type aliases in workflow JSON; custom SerializationTypeResolver mappings that map aliases to open generics; serialization of generic base types without concrete discriminators.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Cannot determine the element type of array
- Expected end of object.
- Expected start of object.
- Failed to extract activity type property
- Failed to parse JsonDocument
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/523f740bb9e5c688.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Serialization/Converters/PolymorphicObjectConverter.cs:398
private void WarnAboutUnaliasedType(Type type)
{
// Check the level before claiming the once-per-type slot: claiming it first would spend the type's single
// report on a call that logs nothing, and the type would then stay silent if the level is raised later.
if (_logger == null || !_logger.IsEnabled(LogLevel.Warning) || !ReportedUnaliasedTypes.TryAdd(type, 0))
return;
_logger.LogWarning(
"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}. " +
"Register it during startup with AddTypeAlias<{PayloadTypeName}>(), or use a Dictionary<string, object> if a property bag is what you intend.",
type,
type,
type.Name);
}
private static Type GetInstantiableTargetType(Type targetType)
{
if (targetType.ContainsGenericParameters)
throw new JsonException($"Workflow JSON type alias resolved to open generic type '{targetType}'.");
if (!targetType.IsInterface && !targetType.IsAbstract)
return targetType;
if (SerializationTypeResolver.TryGetInstantiableCollectionType(targetType, out var instantiableCollectionType))
return instantiableCollectionType;
throw new JsonException($"Workflow JSON type alias resolved to non-instantiable type '{targetType}'.");
}
private static object ReadPrimitive(ref Utf8JsonReader reader, JsonSerializerOptions options)
{
return (reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number when reader.TryGetInt64(out var l) => l,
JsonTokenType.Number => reader.GetDouble(),View on GitHub (pinned to fe9217bdfa)