elsa-workflows/elsa-core · error · InvalidOperationException

A already exists with ' ' in tenant ' '.

Error message

A {entityType} already exists with {keyName} '{key}' in tenant '{tenantId}'.

What it means

MemoryIdentityUniqueness.EnsureAvailable checks an in-memory entity set for another entity of the same type in the same tenant with an equal key (by keySelector) but a different Id. If such a candidate exists it throws InvalidOperationException, since creating/updating the entity would violate the uniqueness constraint (e.g. a duplicate user name or application name within a tenant).

Solutions

  1. Before creating/renaming, query the store for an entity with the same key in the tenant and reuse or reject it in application code.
  2. Make startup seeding idempotent: look up the entity by key first and update it rather than adding a new one.
  3. If the key is genuinely distinct, verify the tenant ID is correct - the conflict is scoped per tenant, so a wrong tenant can surface an apparent collision.
  4. Use a real persistence provider with a unique index if stronger guarantees than the in-memory store are needed.

Example fix

// before
await userManager.CreateAsync(new User { Name = "admin", TenantId = tenantId });
// after
var existing = await userManager.FindByNameAsync("admin", tenantId);
if (existing is null)
    await userManager.CreateAsync(new User { Name = "admin", TenantId = tenantId });
Defensive patterns

Strategy: validation

Validate before calling

var duplicate = (await userRegistry.ListAsync(tenantId)).Any(u => u.Name == candidateName);
if (duplicate) throw new InvalidOperationException($"A user named '{candidateName}' already exists in tenant '{tenantId}'.");

Try / catch

try { await EnsureAvailableAndCreateAsync(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already exists with"))
{
    // handle duplicate: reuse existing entity or surface validation message
}

Prevention

When it happens

Trigger: Calling identity APIs that create or rename users/applications/roles via the in-memory identity store when the requested key (e.g. user name) already exists on a different entity within the same tenant. The generic message interpolates the entity type name, key name, key value, and tenant ID.

Common situations: Seeding identity data twice on application startup without idempotency checks, registering two users with the same name in one tenant, renaming an entity to a name already taken by another entity, or running multiple seeds concurrently against the shared in-memory store in tests.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.Identity/Services/MemoryIdentityUniqueness.cs:31

    /// Throws when another Id in the same tenant already owns <paramref name="keySelector"/>.
    /// Same-Id upserts are allowed so a row can rename itself.
    /// </summary>
    public static void EnsureAvailable<T>(
        MemoryStore<T> store,
        T entity,
        Func<T, string?> keySelector,
        string keyName)
        where T : Entity
    {
        var key = keySelector(entity);
        var existing = store.Find(candidate =>
            candidate.TenantId == entity.TenantId
            && candidate.Id != entity.Id
            && keySelector(candidate) == key);

        if (existing is not null)
        {
            throw new InvalidOperationException(
                $"A {typeof(T).Name.ToLowerInvariant()} already exists with {keyName} '{key}' in tenant '{entity.TenantId}'.");
        }
    }
}

View on GitHub (pinned to fe9217bdfa)