elsa-workflows/elsa-core · error · ArgumentException

Invitation verifier names and allowed actions are required.

Error message

Invitation verifier names and allowed actions are required.

What it means

Normalize() requires every invitation in a UserTaskDefinition to have a non-empty VerifierName, at least one AllowedActions entry, and no blank entries inside AllowedActions. Violating any of these throws an ArgumentException naming Invitations. Invitations gate who can act on the task and with which actions, so empty or malformed ones are unusable.

Solutions

  1. Ensure each invitation has a VerifierName and at least one valid allowed action key before normalizing.
  2. Filter out empty/blank strings from AllowedActions during construction.
  3. Drop invitations that are only partially filled rather than shipping them in the definition.

Example fix

// before
Invitations = [ new() { VerifierName = "", AllowedActions = [] } ]
// after
Invitations = [ new() { VerifierName = "Managers", AllowedActions = ["Approve"] } ]
Defensive patterns

Strategy: validation

Validate before calling

var bad = definition.Invitations.Where(i =>
    string.IsNullOrWhiteSpace(i.VerifierName) ||
    i.AllowedActions.Count == 0 ||
    i.AllowedActions.Any(string.IsNullOrWhiteSpace)).ToList();
if (bad.Count > 0) throw new InvalidOperationException("Invalid invitations: fill verifier name and allowed actions.");

Try / catch

try { definition = definition.Normalize(); }
catch (ArgumentException ex) when (ex.Message.Contains("verifier names")) { /* prompt user to complete invitations */ }

Prevention

When it happens

Trigger: Calling Normalize() on a definition whose Invitations contain an entry with a null/whitespace VerifierName, an empty AllowedActions list, or an AllowedActions list containing null/empty strings — often from deserializing partial JSON or programmatically building invitations without filling all fields.

Common situations: Admin UIs that create an invitation row before the user fills fields; bulk imports from CSV/JSON with missing columns; copies of definitions where AllowedActions were cleared.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.UserTasks/Models/UserTaskModels.cs:217

    public UserTaskDefinitionSnapshot Normalize()
    {
        var actions = Actions.Count == 0
            ? [new UserTaskAction("Complete", "Complete")]
            : Actions;

        if (string.IsNullOrWhiteSpace(Title))
            throw new ArgumentException("A User Task title is required.", nameof(Title));
        if (actions.Any(x => string.IsNullOrWhiteSpace(x.Key) || string.IsNullOrWhiteSpace(x.Label)))
            throw new ArgumentException("User Task action keys and labels are required.", nameof(Actions));
        if (actions.Any(x => string.Equals(x.Key, "Timeout", StringComparison.OrdinalIgnoreCase) || string.Equals(x.Key, "Cancelled", StringComparison.OrdinalIgnoreCase)))
            throw new ArgumentException("Timeout and Cancelled are reserved User Task action keys.");
        if (actions.Select(x => x.Key).Distinct(StringComparer.OrdinalIgnoreCase).Count() != actions.Count)
            throw new ArgumentException("User Task action keys must be unique.");
        if (Priority is < 0 or > 100)
            throw new ArgumentOutOfRangeException(nameof(Priority), "Priority must be between 0 and 100.");
        if (Invitations.Any(x => string.IsNullOrWhiteSpace(x.VerifierName) || x.AllowedActions.Count == 0 || x.AllowedActions.Any(string.IsNullOrWhiteSpace)))
            throw new ArgumentException("Invitation verifier names and allowed actions are required.", nameof(Invitations));
        if (Invitations.Any(invitation => invitation.AllowedActions.Any(allowed => !actions.Any(action => string.Equals(action.Key, allowed, StringComparison.OrdinalIgnoreCase)))))
            throw new ArgumentException("Invitation actions must be configured User Task actions.", nameof(Invitations));

        return this with { Actions = actions };
    }
}

public sealed class UserTask
{
    public string Id { get; set; } = Guid.NewGuid().ToString("N");
    public string TenantId { get; set; } = "";
    public string WorkflowDefinitionId { get; set; } = "";
    public string? WorkflowDefinitionName { get; set; }
    public int? WorkflowDefinitionVersion { get; set; }
    public string WorkflowInstanceId { get; set; } = "";
    /// <summary>A safe, host-authored instance reference (correlation ID or instance name). Never a bookmark or token.</summary>
    public string? WorkflowInstanceReference { get; set; }
    public string ActivityInstanceId { get; set; } = "";

View on GitHub (pinned to fe9217bdfa)