elsa-workflows/elsa-core · error · ArgumentException

User Task protected payload exceeds the configured limit.

Error message

User Task protected payload exceeds the configured limit.

What it means

DefaultUserTaskManager.ProjectAsync checks the materialized task's protected payload size before persisting: both the serialized TaskData and the UTF-8 byte length of Instructions must fit within UserTasksOptions.MaximumPayloadBytes. If either exceeds the limit, an ArgumentException is thrown and the task is not created. This protects the store and downstream consumers from oversized payloads.

Solutions

  1. Reduce the payload: trim TaskData to only what the task form needs and shorten instructions.
  2. Increase UserTasksOptions.MaximumPayloadBytes in configuration if the limit is genuinely too small for your use case.
  3. Store large blobs externally (file/object storage) and pass a reference/URL in TaskData instead.

Example fix

// before
services.Configure<UserTasksOptions>(o => o.MaximumPayloadBytes = 8 * 1024);
// after
services.Configure<UserTasksOptions>(o => o.MaximumPayloadBytes = 64 * 1024);
Defensive patterns

Strategy: validation

Validate before calling

var bytes = Encoding.UTF8.GetByteCount(JsonSerializer.Serialize(materialization.Definition.TaskData ?? new object()));
if (bytes > options.MaximumPayloadBytes) throw new InvalidOperationException("Task data exceeds payload limit.");

Try / catch

try { await manager.ProjectAsync(materialization, ct); }
catch (ArgumentException ex) when (ex.Message.Contains("payload exceeds")) { /* shrink payload and retry */ }

Prevention

When it happens

Trigger: Materializing a User Task whose TaskData JSON exceeds the configured byte limit, or whose Instructions string is longer than the limit in bytes (multi-byte characters count more than characters); calling ProjectAsync with a large form payload or very long instructions.

Common situations: Users pasting long text into task instructions; passing large documents/arrays as task data instead of a reference; MaximumPayloadBytes lowered via options (e.g. from a default to a stricter value) so previously valid payloads now fail.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.UserTasks/Services/DefaultUserTaskManager.cs:31

    IUserTaskRepository repository,
    IUserTaskAccessPolicy accessPolicy,
    IEnumerable<IUserTaskFormProvider> formProviders,
    IUserTaskWorkflowResumer workflowResumer,
    IUserTaskNotificationSink notificationSink,
    IIdentityGenerator identityGenerator,
    ISystemClock clock,
    Microsoft.Extensions.Options.IOptions<UserTasksOptions> options,
    IUserTaskParticipantDirectory? participantDirectory = null) : IUserTaskManager
{
    private readonly IReadOnlyDictionary<string, IUserTaskFormProvider> _formProviders = formProviders
        .ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase);
    private readonly UserTasksOptions _options = options.Value;

    public async Task<UserTaskProjectionResult> ProjectAsync(UserTaskMaterialization materialization, CancellationToken cancellationToken = default)
    {
        var definition = materialization.Definition.Normalize();
        if (PayloadBytes(definition.TaskData) > _options.MaximumPayloadBytes || Encoding.UTF8.GetByteCount(definition.Instructions ?? "") > _options.MaximumPayloadBytes)
            throw new ArgumentException("User Task protected payload exceeds the configured limit.");
        var existing = await repository.FindByMaterializationKeyAsync(materialization.TenantId, MaterializationKey(materialization), cancellationToken);
        if (existing != null)
            return new UserTaskProjectionResult(existing, false);

        ResolvedUserTaskForm? pinnedForm = null;
        var healthSeverity = (UserTaskHealthSeverity?)null;
        string? healthCode = null;
        string? healthMessage = null;
        var snapshotMembers = materialization.SnapshotMembers.ToList();
        var snapshotGroups = materialization.SnapshotGroups.ToList();
        if (definition.MembershipResolutionMode == UserTaskMembershipResolutionMode.Snapshot)
        {
            snapshotMembers.AddRange(definition.CandidateUsers);
            snapshotGroups.AddRange(definition.CandidateGroups);
            if (participantDirectory != null)
            {
                foreach (var group in definition.CandidateGroups)
                {

View on GitHub (pinned to fe9217bdfa)