elsa-workflows/elsa-core · error · DataProcessingException

Unable to save data

Error message

Unable to save data

What it means

Same handler as the 23505 branch: any DbUpdateException whose inner exception is NOT a unique violation (or has no PostgresException inner) is rethrown as a generic DataProcessingException('Unable to save data', exception). It wraps all non-unique-constraint PostgreSQL save failures so callers get a consistent Elsa persistence exception type while retaining the original as InnerException.

Solutions

  1. Inspect ex.InnerException (PostgresException) for SqlState and Message to identify the real cause.
  2. Fix the underlying data/model issue (add missing migration, fix FK references, supply required fields).
  3. Retry transient failures (connection resets, serialization failures) with a retry policy.
  4. Catch DataProcessingException around persistence calls and log the inner exception details.

Example fix

// before
await repository.SaveAsync(entity);
// after
try { await repository.SaveAsync(entity); }
catch (DataProcessingException ex) when (ex.InnerException is PostgresException pg && pg.SqlState == "23503")
{
    // handle FK violation
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate required fields and FK references before saving
if (string.IsNullOrWhiteSpace(entity.RequiredField))
    throw new InvalidOperationException("RequiredField must be set before saving");
var fkOk = await parents.AnyAsync(p => p.Id == entity.ParentId, ct);
if (!fkOk) throw new InvalidOperationException("ParentId references a missing parent");

Type guard

static bool IsTransient(DataProcessingException ex) =>
    ex.InnerException is PostgresException { SqlState: "40001" or "40P01" or "08006" or "08003" };

Try / catch

try
{
    await repository.SaveAsync(entity, ct);
}
catch (DataProcessingException ex)
{
    var pg = ex.InnerException as PostgresException;
    logger.LogError(pg, "Save failed with SqlState {SqlState}", pg?.SqlState);
    if (IsTransient(ex)) await RetrySaveAsync(entity, ct); // retry transient failures
    else throw;
}

Prevention

When it happens

Trigger: Calling a repository/SaveChanges operation against PostgreSQL where the update fails for reasons other than a 23505 unique violation: foreign key violations (23503), not-null violations (23502), deadlocks, serialization failures, connectivity loss during commit.

Common situations: Deleting a parent record still referenced by children (FK violation); missing required column values after a model change without a migration; transient network/database outages; concurrent modification conflicts.

Related errors


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

Appendix: source

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

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)