elsa-workflows/elsa-core · error · UniqueKeyConstraintViolationException

23505

23505

Error message

Unable to save data

What it means

The PostgreSQL DbExceptionTransformer handler converts EF Core DbUpdateException whose inner PostgresException has SqlState 23505 (unique_violation) into Elsa's UniqueKeyConstraintViolationException with message 'Unable to save data'. This normalizes provider-specific constraint errors into a typed exception the application/persistence layer can handle.

Solutions

  1. Catch UniqueKeyConstraintViolationException around save operations and implement idempotent upsert/skip logic.
  2. Check the violated key in the inner exception's Detail/ConstraintName to see which unique index fired.
  3. Deduplicate existing rows in the table if a new migration introduced a unique index over non-unique data.
  4. Use deterministic IDs or optimistic concurrency instead of relying on auto-generated values that can collide.

Example fix

// before
await dbContext.SaveChangesAsync();
// after
try { await dbContext.SaveChangesAsync(); }
catch (UniqueKeyConstraintViolationException ex)
{
    // handle duplicate key, e.g. load existing and update instead of insert
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check for existence before insert where possible
var exists = await dbSet.AnyAsync(x => x.Id == entity.Id, ct);
if (exists) return await UpdateExistingAsync(entity, ct);

Try / catch

try
{
    await dbContext.SaveChangesAsync(ct);
}
catch (UniqueKeyConstraintViolationException ex)
{
    logger.LogInformation(ex.InnerException, "Duplicate key on save; applying idempotent handling");
    // upsert or skip
}

Prevention

When it happens

Trigger: Saving entities via EF Core SaveChanges when a UNIQUE constraint or unique index is violated in PostgreSQL (SqlState 23505) — e.g. inserting a duplicate workflow instance ID, duplicate definition version, or any key uniqueness conflict.

Common situations: Race condition where two concurrent workflow executions create the same record; re-importing/re-registering the same workflow definition; seeding data that already exists; unique index added by migrations conflicting with legacy duplicate rows.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/35b94c2522e22cef. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Persistence.EFCore.PostgreSql/Handlers/DbExceptionTransformer.cs:18

using Elsa.Workflows.Exceptions;
using JetBrains.Annotations;
using Npgsql;

namespace Elsa.Persistence.EFCore.PostgreSql.Handlers;

/// <summary>
/// Transforms database exceptions encountered when using a postgreSQL database into more generic exceptions.
/// </summary>
[UsedImplicitly]
public class DbExceptionTransformer : IDbExceptionHandler
{
    public Task HandleAsync(DbUpdateExceptionContext context)
    {
        var exception = context.Exception;
        
        if (exception.InnerException is PostgresException { SqlState: "23505" })
            throw new UniqueKeyConstraintViolationException("Unable to save data", exception);

        throw new DataProcessingException("Unable to save data", exception);
    }
}

View on GitHub (pinned to fe9217bdfa)