elsa-workflows/elsa-core · error · ArgumentException
Invitation actions must be configured User Task actions.
Error message
Invitation actions must be configured User Task actions.
What it means
Normalize() cross-checks that every AllowedActions entry on each invitation references an action key that exists in the definition's Actions list (case-insensitive). If an invitation names an action that is not configured, the ArgumentException is thrown. This keeps invitations from granting actions the task cannot deliver.
Solutions
- Update each invitation's AllowedActions to reference existing action keys after changing Actions.
- Validate and fix definitions after any rename/migration of action keys.
- Trim and normalize action keys when authoring to avoid whitespace/case mismatches.
Example fix
// before
Actions = [new() { Key = "Reject", Label = "Reject" }],
Invitations = [new() { VerifierName = "Managers", AllowedActions = ["Rejected"] }]
// after
Invitations = [new() { VerifierName = "Managers", AllowedActions = ["Reject"] }] Defensive patterns
Strategy: validation
Validate before calling
var keys = definition.Actions.Select(a => a.Key).ToHashSet(StringComparer.OrdinalIgnoreCase);
var dangling = definition.Invitations.SelectMany(i => i.AllowedActions).Where(a => !keys.Contains(a)).ToList();
if (dangling.Count > 0) throw new InvalidOperationException($"Unknown action keys: {string.Join(", ", dangling)}"); Try / catch
try { definition = definition.Normalize(); }
catch (ArgumentException ex) when (ex.Message.Contains("configured User Task actions")) { /* re-map invitation actions */ } Prevention
- Treat invitation AllowedActions as foreign keys and update them in the same change as action renames
- Run Normalize() as part of your definition CI/linting
- Provide UI dropdowns populated from the actual action list instead of free-text
When it happens
Trigger: Renaming or deleting a User Task action (e.g. 'Rejected' → 'Reject') without updating Invitations' AllowedActions; hand-authored definitions where invitations were copied from another task; typo in an allowed action key.
Common situations: Definition versioning/migration where action sets changed; copy-paste between task definitions; spelling differences like 'approve ' with a trailing space.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Timeout and Cancelled are reserved User Task action keys.
- User Task action keys must be unique.
- Invitation verifier names and allowed actions are required.
- 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/e26b542c132c041b.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.UserTasks/Models/UserTaskModels.cs:219
{
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; } = "";
public string BookmarkId { get; set; } = "";
public string MaterializationKey { get; set; } = "";View on GitHub (pinned to fe9217bdfa)