{"record":{"id":"607fd88853b33a7d","repo":"elsa-workflows/elsa-core","slug":"failed-to-extract-activity-type-property","errorCode":null,"errorMessage":"Failed to extract activity type property","messagePattern":"Failed to extract activity type property","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs","lineNumber":108,"sourceCode":"            logger.LogWarning(\"An exception was thrown while constructing activity with id '{activityId}': {Message}\", result.Activity.Id, exception.Message);\n    }\n\n    /// <inheritdoc />\n    public override void Write(Utf8JsonWriter writer, IActivity value, JsonSerializerOptions options)\n    {\n        var clonedOptions = GetClonedWriterOptions(options);\n        var activityDescriptor = activityRegistry.Find(value.Type, value.Version);\n\n        // Give the activity descriptor a chance to customize the serializer options.\n        clonedOptions = activityDescriptor?.ConfigureSerializerOptions?.Invoke(clonedOptions) ?? clonedOptions;\n\n        activityWriter.WriteActivity(writer, value, clonedOptions);\n    }\n\n    private string GetActivityDetails(JsonElement activityRoot, out int activityTypeVersion, out ActivityDescriptor? activityDescriptor)\n    {\n        if (!activityRoot.TryGetProperty(\"type\", out var activityTypeNameElement))\n            throw new JsonException(\"Failed to extract activity type property\");\n\n        var activityTypeName = activityTypeNameElement.GetString()!;\n        activityDescriptor = null;\n        activityTypeVersion = 0;\n\n        // First, we check whether the activity type name is a 'well-known' activity; not a workflow-as-activity\n\n        // If the activity type version is specified, use that to find the activity descriptor.\n        if (activityRoot.TryGetProperty(\"version\", out var activityVersionElement))\n        {\n            activityTypeVersion = activityVersionElement.GetInt32();\n            activityDescriptor = activityRegistry.Find(activityTypeName, activityTypeVersion);\n        }\n\n        // If a version is not specified, or activity with specified version is not found: use the latest version of the activity descriptor.\n        if (activityDescriptor == null)\n        {\n            activityDescriptor = activityRegistry.Find(activityTypeName);","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs#L90-L126","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Add the required \"type\" property with the activity's registered type name (e.g. \"type\": \"HttpEndpoint\").","If versioned, include the activity version field as produced by a normal Elsa export.","Re-export the workflow from Elsa Studio/Designer to get a canonical payload instead of hand-writing JSON."],"exampleFix":"// before\n{ \"id\": \"step-1\", \"properties\": {} }\n\n// after\n{ \"type\": \"WriteLine\", \"id\": \"step-1\", \"properties\": {} }","handlingStrategy":"validation","validationCode":"using var doc = JsonDocument.Parse(json);\nif (doc.RootElement.ValueKind != JsonValueKind.Object || !doc.RootElement.TryGetProperty(\"type\", out _))\n    throw new InvalidOperationException(\"Activity JSON must contain a 'type' property\");","typeGuard":"static bool HasActivityType(JsonElement e) => e.ValueKind == JsonValueKind.Object && e.TryGetProperty(\"type\", out var t) && t.ValueKind == JsonValueKind.String && !string.IsNullOrEmpty(t.GetString());","tryCatchPattern":"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\"); }","preventionTips":["Always include \"type\" in hand-authored activity JSON","Prefer re-exporting workflows from Elsa Studio over manual JSON editing","Watch out for middleware/serializers configured with IgnoreNullValues or property filters that strip discriminators"],"tags":["csharp","json","serialization","discriminator"],"backgroundTag":"schema-validation-failed","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}