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

  1. Assign proposal.Id (e.g. Guid.NewGuid().ToString()) before SaveAsync.
  2. Fix the ID-generation strategy or mapper so Id is always populated.
  3. 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

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


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)