elsa-workflows/elsa-core · error · ArgumentException
A proposal ID is required.
Error message
A proposal ID is required.
What it means
The proposal store's Validate method requires a non-whitespace Id before persisting an AIProposal. The Id is the primary key of AIProposalRecord; ArgumentException (paramName 'proposal') is thrown when it is missing so the store never inserts a record without an identifier.
Solutions
- Assign proposal.Id (e.g. Guid.NewGuid().ToString()) before SaveAsync.
- Fix the ID-generation strategy or mapper so Id is always populated.
- Add a pre-save guard in your service to reject proposals without an ID.
Example fix
// before
var proposal = new AIProposal { ConversationId = cid, CreatedBy = user };
await proposalStore.SaveAsync(proposal);
// after
var proposal = new AIProposal { Id = Guid.NewGuid().ToString(), ConversationId = cid, CreatedBy = user };
await proposalStore.SaveAsync(proposal); Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrWhiteSpace(proposal.Id)) throw new ArgumentException("A proposal ID is required before SaveAsync."); Type guard
static bool HasId(AIProposal p) => !string.IsNullOrWhiteSpace(p.Id);
Try / catch
try { await proposalStore.SaveAsync(proposal); }
catch (ArgumentException ex) when (ex.ParamName == "proposal" && ex.Message.Contains("proposal ID")) { /* generate/assign an ID and retry once */ } Prevention
- Generate Id in the proposal factory or constructor.
- Validate proposal fields before calling the store.
- Verify mappers/deserializers populate Id.
- Prefer Guid-based IDs to avoid deterministic collisions.
When it happens
Trigger: Calling SaveAsync with an AIProposal whose Id is null, empty, or whitespace — this is the first check, so it fires before the ConversationId and CreatedBy checks.
Common situations: Manually constructed AIProposal without Id; a generator/strategy returning null IDs; JSON deserialization dropping the Id field; tests creating proposals via object initializers missing the Id.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- A proposal conversation ID is required.
- A conversation ID is required. (Parameter 'conversation')
- A conversation user ID is required. (Parameter…
- A proposal creator is required.
- A conversation ID is required. (Parameter 'conversation')
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/ae75a6e94b75a02d.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIProposalStore.cs:132
private static TEnum ParseEnum<TEnum>(string value, TEnum defaultValue) where TEnum : struct =>
Enum.TryParse<TEnum>(value, ignoreCase: true, out var result) ? result : defaultValue;
private static bool BelongsToTenant(string? storedTenantId, string? requestedTenantId) =>
string.Equals(NormalizeTenantId(storedTenantId), NormalizeTenantId(requestedTenantId), StringComparison.Ordinal);
private static string NormalizeTenantId(string? tenantId) => tenantId ?? "";
private static void ValidateUserOwnership(AIProposalRecord record, AIProposal proposal)
{
if (!string.IsNullOrWhiteSpace(record.CreatedBy) && !string.Equals(record.CreatedBy, proposal.CreatedBy, StringComparison.Ordinal))
throw new InvalidOperationException("Cannot overwrite an AI proposal that belongs to another user.");
}
private static void Validate(AIProposal proposal)
{
if (string.IsNullOrWhiteSpace(proposal.Id))
throw new ArgumentException("A proposal ID is required.", nameof(proposal));
if (string.IsNullOrWhiteSpace(proposal.ConversationId))
throw new ArgumentException("A proposal conversation ID is required.", nameof(proposal));
if (string.IsNullOrWhiteSpace(proposal.CreatedBy))
throw new ArgumentException("A proposal creator is required.", nameof(proposal));
}
}
View on GitHub (pinned to fe9217bdfa)