elsa-workflows/elsa-core · error · JsonException

Failed to extract activity type property

Error message

Failed to extract activity type property

What it means

GetActivityDetails reads the required 'type' property from a JSON activity object to determine which activity to instantiate. If the JSON object has no 'type' property, this JsonException is thrown. Every serialized Elsa activity must carry a 'type' discriminator.

Solutions

  1. Add the required "type" property with the activity's registered type name (e.g. "type": "HttpEndpoint").
  2. If versioned, include the activity version field as produced by a normal Elsa export.
  3. Re-export the workflow from Elsa Studio/Designer to get a canonical payload instead of hand-writing JSON.

Example fix

// before
{ "id": "step-1", "properties": {} }

// after
{ "type": "WriteLine", "id": "step-1", "properties": {} }
Defensive patterns

Strategy: validation

Validate before calling

using var doc = JsonDocument.Parse(json);
if (doc.RootElement.ValueKind != JsonValueKind.Object || !doc.RootElement.TryGetProperty("type", out _))
    throw new InvalidOperationException("Activity JSON must contain a 'type' property");

Type guard

static bool HasActivityType(JsonElement e) => e.ValueKind == JsonValueKind.Object && e.TryGetProperty("type", out var t) && t.ValueKind == JsonValueKind.String && !string.IsNullOrEmpty(t.GetString());

Try / catch

try { var activity = JsonSerializer.Deserialize<IActivity>(json); } catch (JsonException ex) when (ex.Message.Contains("Failed to extract activity type property")) { log.LogError(ex, "Activity JSON missing 'type' discriminator"); }

Prevention

When it happens

Trigger: Deserializing an activity JSON object that lacks a 'type' member — e.g. {"id":"x"} or JSON produced by tools that strip the discriminator — encountered in ActivityJsonConverter.GetActivityDetails (src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs:108).

Common situations: Manually authoring composite or custom activity JSON without 'type'; third-party serializers stripping unknown properties; transforming workflow JSON with jq/JSON tools that drop fields.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/607fd88853b33a7d. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs:108

            logger.LogWarning("An exception was thrown while constructing activity with id '{activityId}': {Message}", result.Activity.Id, exception.Message);
    }

    /// <inheritdoc />
    public override void Write(Utf8JsonWriter writer, IActivity value, JsonSerializerOptions options)
    {
        var clonedOptions = GetClonedWriterOptions(options);
        var activityDescriptor = activityRegistry.Find(value.Type, value.Version);

        // Give the activity descriptor a chance to customize the serializer options.
        clonedOptions = activityDescriptor?.ConfigureSerializerOptions?.Invoke(clonedOptions) ?? clonedOptions;

        activityWriter.WriteActivity(writer, value, clonedOptions);
    }

    private string GetActivityDetails(JsonElement activityRoot, out int activityTypeVersion, out ActivityDescriptor? activityDescriptor)
    {
        if (!activityRoot.TryGetProperty("type", out var activityTypeNameElement))
            throw new JsonException("Failed to extract activity type property");

        var activityTypeName = activityTypeNameElement.GetString()!;
        activityDescriptor = null;
        activityTypeVersion = 0;

        // First, we check whether the activity type name is a 'well-known' activity; not a workflow-as-activity

        // If the activity type version is specified, use that to find the activity descriptor.
        if (activityRoot.TryGetProperty("version", out var activityVersionElement))
        {
            activityTypeVersion = activityVersionElement.GetInt32();
            activityDescriptor = activityRegistry.Find(activityTypeName, activityTypeVersion);
        }

        // If a version is not specified, or activity with specified version is not found: use the latest version of the activity descriptor.
        if (activityDescriptor == null)
        {
            activityDescriptor = activityRegistry.Find(activityTypeName);

View on GitHub (pinned to fe9217bdfa)