{"record":{"id":"c2e4cf4c41b80587","repo":"elsa-workflows/elsa-core","slug":"failed-to-insert-ai-proposal-proposal-id-and-no-existing","errorCode":null,"errorMessage":"Failed to insert AI proposal {proposal.Id}, and no existing record was found for retry.","messagePattern":"Failed to insert AI proposal (.+?), and no existing record was found for retry\\.","errorType":"exception","errorClass":"DbUpdateException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIProposalStore.cs","lineNumber":58,"sourceCode":"\n        Map(proposal, record);\n\n        try\n        {\n            await dbContext.SaveChangesAsync(cancellationToken);\n        }\n        catch (DbUpdateException e) when (isNew)\n        {\n            await RetryAsUpdateAsync(proposal, e, cancellationToken);\n        }\n    }\n\n    private async ValueTask RetryAsUpdateAsync(AIProposal proposal, DbUpdateException originalException, CancellationToken cancellationToken)\n    {\n        dbContext.ChangeTracker.Clear();\n        var record = await dbContext.Proposals.FindAsync([proposal.Id], cancellationToken);\n        if (record == null)\n            throw new DbUpdateException($\"Failed to insert AI proposal {proposal.Id}, and no existing record was found for retry.\", originalException);\n\n        if (!BelongsToTenant(record.TenantId, proposal.TenantId))\n            throw new InvalidOperationException(\"Cannot overwrite an AI proposal that belongs to another tenant.\");\n\n        ValidateUserOwnership(record, proposal);\n\n        Map(proposal, record);\n        await dbContext.SaveChangesAsync(cancellationToken);\n    }\n\n    private static AIProposal Map(AIProposalRecord record) =>\n        new()\n        {\n            Id = record.Id,\n            TenantId = record.TenantId,\n            ConversationId = record.ConversationId,\n            Kind = ParseEnum(record.Kind, AIProposalKind.WorkflowCreate),\n            Status = ParseEnum(record.Status, AIProposalStatus.Draft),","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.AI.Persistence.EFCore/Stores/EFCoreAIProposalStore.cs#L40-L76","documentation":"When the initial insert in SaveAsync fails with a concurrency/key exception, the store retries as an update (RetryAsUpdateAsync). It re-fetches the proposal record with ChangeTracker cleared; if the record no longer exists (deleted between the failed insert and the retry), it wraps the situation in a new DbUpdateException with this message, preserving the original exception as InnerException.","triggerScenarios":"SaveAsync hits a DbUpdateException on insert, RetryAsUpdateAsync runs FindAsync on Proposals, and the record is not found — i.e., the original insert failed on a unique constraint other than the primary key, or the row was deleted concurrently.","commonSituations":"Concurrent deletion of the proposal between insert failure and retry; a unique-index violation on a non-PK column (e.g. conversation/sequence key) causing insert failure where no row with that Id exists; connection/transaction issues making the fetched row invisible.","solutions":["Check originalException.InnerException to find the real insert failure (unique constraint vs. connection).","Add a retry policy around SaveAsync; if the record was concurrently deleted, decide whether to re-insert or surface a not-found error.","Remove conflicting unique indexes that treat legitimate new proposals as duplicates.","Log and investigate concurrent writers to the same proposal Id."],"exampleFix":"// before\nawait proposalStore.SaveAsync(proposal); // DbUpdateException wrapped: \"Failed to insert...\"\n// after\ntry { await proposalStore.SaveAsync(proposal); }\ncatch (DbUpdateException ex) when (ex.InnerException is DbUpdateConcurrencyException) { /* re-fetch and decide */ }","handlingStrategy":"retry","validationCode":"var exists = await dbContext.Proposals.AnyAsync(p => p.Id == proposal.Id);\n// decide: if not exists after failed insert, re-insert or surface a permanent error","typeGuard":null,"tryCatchPattern":"try { await proposalStore.SaveAsync(proposal); }\ncatch (DbUpdateException ex) { logger.LogWarning(ex, \"Insert retry failed for proposal {Id}\", proposal.Id); /* check ex.InnerException; re-fetch and re-insert or fail */ }","preventionTips":["Configure a bounded retry policy for transient DB failures.","Investigate InnerException to distinguish unique-constraint vs. concurrency vs. connectivity failures.","Avoid unique indexes that collide with legitimate new proposals.","Detect and log concurrent writers to the same proposal Id."],"tags":["ef-core","ai-proposals","concurrency","dbupdate"],"backgroundTag":"database-write-failed","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}