elsa-workflows/elsa-core · error · ArgumentException
A proposal conversation ID is required.
Error message
A proposal conversation ID is required.
What it means
The proposal store's Validate method requires a non-whitespace ConversationId on every AIProposal. Proposals are scoped to their parent conversation; a missing ConversationId breaks that linkage and tenant/user ownership checks, so ArgumentException (paramName 'proposal') is thrown.
Solutions
- Set proposal.ConversationId to the parent conversation's Id before SaveAsync.
- Ensure the proposal is created through a flow that has the conversation context available.
- Validate in your service layer that ConversationId is present and the referenced conversation exists.
Example fix
// before
var proposal = new AIProposal { Id = id, CreatedBy = user }; // ConversationId missing
await proposalStore.SaveAsync(proposal);
// after
var proposal = new AIProposal { Id = id, ConversationId = conversation.Id, CreatedBy = user };
await proposalStore.SaveAsync(proposal); Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrWhiteSpace(proposal.ConversationId)) throw new ArgumentException("A proposal ConversationId is required before SaveAsync.");
// optionally: ensure the conversation exists
// if (!await dbContext.Conversations.AnyAsync(c => c.Id == proposal.ConversationId)) throw new InvalidOperationException("Parent conversation not found."); Type guard
static bool HasConversation(AIProposal p) => !string.IsNullOrWhiteSpace(p.ConversationId);
Try / catch
try { await proposalStore.SaveAsync(proposal); }
catch (ArgumentException ex) when (ex.ParamName == "proposal" && ex.Message.Contains("conversation ID")) { /* attach the proposal to a conversation before saving */ } Prevention
- Create proposals only within a conversation-scoped code path.
- Require ConversationId in the API/DTO layer.
- Verify the parent conversation exists before saving.
- Keep proposal construction close to conversation handling so the reference is always available.
When it happens
Trigger: Calling SaveAsync with an AIProposal that has a valid Id but a null/empty/whitespace ConversationId (this check runs after the Id check and before the CreatedBy check).
Common situations: Creating a proposal outside the context of a conversation; a mapper that omits ConversationId; API callers posting proposals without the parent conversation reference; refactors renaming the field and missing the assignment.
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 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/a7c0f2157679fa31.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIProposalStore.cs:135
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)