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

  1. Ensure the type alias in the JSON resolves to a closed generic (e.g. List`1[[MyNamespace.MyItem, MyAssembly]]).
  2. Fix custom type-resolver alias registrations to map to closed, instantiable types.
  3. Use concrete non-generic or closed-generic property types in the model.
  4. 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

When it happens

Trigger: Deserializing JSON with a type alias ($type / type mapping) that resolves to an open generic type such as 'List&lt;&gt;' 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


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)