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
- Ensure each invitation has a VerifierName and at least one valid allowed action key before normalizing.
- Filter out empty/blank strings from AllowedActions during construction.
- 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
- Validate invitation forms client-side before submitting
- Never persist definitions with half-completed invitations
- Centralize invitation construction in a factory that enforces the invariants
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
- Timeout and Cancelled are reserved User Task action keys.
- User Task action keys must be unique.
- Invitation actions must be configured User Task actions.
- User Task protected payload exceeds the configured limit.
- A conversation ID is required. (Parameter 'conversation')
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)