elsa-workflows/elsa-core · error · InvalidOperationException

{error}

Error message

{error}

What it means

This error's message is dynamic: it is whatever error string the secret type provider's ValidateRotation method produced when it rejected the rotation request. RotateAsync calls provider.ValidateRotation and, on failure, throws InvalidOperationException with the provider-supplied message.

Solutions

  1. Read the thrown message - it names the exact validation failure - and correct the RotateSecretRequest accordingly.
  2. Consult the secret type provider's rotation requirements (descriptor/documentation) and supply all required fields.
  3. Test the request against provider.ValidateRotation in a pre-check before calling RotateAsync.
  4. Catch InvalidOperationException around RotateAsync to surface the provider error to the user.

Example fix

// before
await manager.RotateAsync("api-key", new RotateSecretRequest { Value = "" }); // provider rejects empty value
// after
var request = new RotateSecretRequest { Value = newKey };
if (!provider.ValidateRotation(request, storeName, out var error))
    throw new InvalidOperationException("Fix rotation request: " + error);
await manager.RotateAsync("api-key", request);
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check using the same provider used by the manager
if (!typeRegistry.Get(secret.TypeName).ValidateRotation(request, secret.StoreName, out var error)) throw new InvalidOperationException(error);

Try / catch

try { await manager.RotateAsync(name, request); }
catch (InvalidOperationException e) { /* surface e.Message - it is the provider's validation error */ }

Prevention

When it happens

Trigger: Calling ISecretManager.RotateAsync with a RotateSecretRequest that fails the specific secret type provider's validation rules - e.g. missing required fields, invalid value format for that secret type, or disallowed rotation parameters.

Common situations: Rotating a custom secret type whose rotation requirements (e.g. new value length/format, required metadata) are not met; API clients sending the same body used for a different secret type.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretManager.cs:70

        var secret = await GetExistingAsync(name, cancellationToken);

        secret.DisplayName = string.IsNullOrWhiteSpace(request.DisplayName) ? secret.Name : request.DisplayName.Trim();
        secret.Description = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim();
        secret.UpdatedAt = DateTimeOffset.UtcNow;

        await repository.SaveAsync(secret, cancellationToken);
        return secret;
    }

    public async Task<Secret> RotateAsync(string name, RotateSecretRequest request, CancellationToken cancellationToken = default)
    {
        var secret = await GetExistingAsync(name, cancellationToken);
        if (secret.Status == SecretStatus.Revoked)
            throw new InvalidOperationException($"Secret '{secret.Name}' is revoked and cannot be rotated.");

        var provider = typeRegistry.Get(secret.TypeName);
        if (!provider.ValidateRotation(request, secret.StoreName, out var error))
            throw new InvalidOperationException(error);

        var store = storeRegistry.Get(secret.StoreName);
        EnsureCanWrite(store);
        var nextVersion = secret.Versions.Count == 0 ? 1 : secret.Versions.Max(x => x.Version) + 1;
        var version = new SecretVersion { Version = nextVersion, ExpiresAt = request.ExpiresAt };
        version.Payload = await store.WriteAsync(secret, version, CreatePayload(request), cancellationToken);

        foreach (var activeVersion in secret.Versions.Where(x => x.Status == SecretStatus.Active))
            activeVersion.Status = SecretStatus.Retired;

        secret.Versions.Add(version);
        secret.Status = SecretStatus.Active;
        secret.UpdatedAt = DateTimeOffset.UtcNow;
        await repository.SaveAsync(secret, cancellationToken);

        return secret;
    }

View on GitHub (pinned to fe9217bdfa)