elsa-workflows/elsa-core · error · InvalidOperationException
A secret named ' ' already exists.
Error message
A secret named '{request.Name}' already exists. What it means
Thrown by DefaultSecretManager.CreateAsync when the repository refuses to add the newly created secret because an active (non-deleted) secret with the same name already exists. CreateAsync is create-only; rotating or updating an existing secret requires the dedicated APIs.
Solutions
- Call manager.GetAsync(name) first; if a secret exists, use RotateAsync or UpdateAsync instead of CreateAsync.
- Catch InvalidOperationException from CreateAsync and fall back to the update/rotate path.
- Generate unique names or include a scope/environment prefix to avoid collisions.
- Make provisioning scripts idempotent (create-if-missing).
Example fix
// before
await manager.CreateAsync(new CreateSecretRequest { Name = "db-password", Value = v });
// after
if (await manager.GetAsync("db-password") is null)
await manager.CreateAsync(new CreateSecretRequest { Name = "db-password", Value = v });
else
await manager.RotateAsync("db-password", new RotateSecretRequest { Value = v }); Defensive patterns
Strategy: try-catch
Validate before calling
if (await manager.GetAsync(request.Name) != null) throw new InvalidOperationException($"Secret '{request.Name}' exists; use rotate/update."); Try / catch
try { await manager.CreateAsync(request); }
catch (InvalidOperationException e) when (e.Message.Contains("already exists")) { await manager.RotateAsync(request.Name, rotateFrom(request)); } Prevention
- Implement create-or-rotate logic instead of blind create.
- Expose clear UI/API errors when a name is taken before submit.
- Use unique names per environment/scope.
When it happens
Trigger: Calling ISecretManager.CreateAsync(new CreateSecretRequest { Name = "existing-name", ... }) when a secret with that name (case-insensitive) already exists and TryAddOrReplaceDeletedAsync returns false.
Common situations: Re-running secret provisioning after a previous successful run, users submitting a create form for a name that already exists, or automated pipelines without idempotency.
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
- A secret named ' ' already exists.
- A secret named ' ' already exists.
- A secret named ' ' already exists.
- A secret named ' ' already exists.
- A secret named ' ' already exists.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/9f88ff5ee3dca420.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretManager.cs:10
namespace Elsa.Secrets.Services;
public class DefaultSecretManager(ISecretNameValidator nameValidator, ISecretStoreRegistry storeRegistry, ISecretTypeRegistry typeRegistry, ISecretRepository repository) : ISecretManager
{
public async Task<Secret> CreateAsync(CreateSecretRequest request, CancellationToken cancellationToken = default)
{
ValidateName(request.Name);
var secret = await CreateSecretAsync(request, cancellationToken);
if (!await repository.TryAddOrReplaceDeletedAsync(secret, cancellationToken))
throw new InvalidOperationException($"A secret named '{request.Name}' already exists.");
return secret;
}
public async Task<Secret?> GetAsync(string name, CancellationToken cancellationToken = default)
{
var secret = await repository.GetAsync(nameValidator.Normalize(name), cancellationToken);
return secret is { Status: SecretStatus.Deleted } ? null : secret;
}
public async Task<IReadOnlyCollection<Secret>> ListAsync(ListSecretsRequest request, CancellationToken cancellationToken = default)
{
return (await ListPageAsync(request, cancellationToken)).Items;
}
public async Task<ListSecretsResult> ListPageAsync(ListSecretsRequest request, CancellationToken cancellationToken = default)
{
var secrets = await repository.ListAsync(cancellationToken);View on GitHub (pinned to fe9217bdfa)