elsa-workflows/elsa-core · error · InvalidOperationException
Secret ' ' could not be resolved.
Error message
Secret '{secret.Name}' could not be resolved. What it means
Thrown by DefaultSecretManager.ResolvePayloadAsync when the secret store returns a null payload or a payload with a null Value for the secret's latest active version. It means the secret is registered and active, but its actual value could not be read from the backing store.
Solutions
- Verify the value still exists in the backing store for the secret's StoreName and re-write it if missing (store.WriteAsync or rotate the secret).
- For configuration-backed stores, check that the configuration key (often in payload Metadata 'configurationKey') is present in appsettings/environment.
- Rotate the secret to write a fresh value: manager.RotateAsync(name, new RotateSecretRequest { Value = ... }).
- Catch InvalidOperationException around ResolvePayloadAsync and fall back to a default or fail fast with a clear message.
Example fix
// before
var payload = await manager.ResolvePayloadAsync("api-key"); // throws if value gone
// after
try { var payload = await manager.ResolvePayloadAsync("api-key"); }
catch (InvalidOperationException) { await manager.RotateAsync("api-key", new RotateSecretRequest { Value = freshValue }); } Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the backing value exists before resolving
var secret = await manager.GetAsync(name);
var present = secret is { Status: SecretStatus.Active } && await storeRegistry.Get(secret.StoreName).TestAsync(secret, secret.LatestActiveVersion!, ct); Try / catch
try { var payload = await manager.ResolvePayloadAsync(name); }
catch (InvalidOperationException e) when (e.Message.Contains("could not be resolved")) { /* alert ops; rotate or restore the store value */ } Prevention
- Monitor configuration-backed keys referenced by secrets (configurationKey metadata).
- Use TestAsync as a health probe for secret stores.
- Never delete backing values without revoking/rotating the secret first.
When it happens
Trigger: Calling ISecretManager.ResolvePayloadAsync(name or secret) where store.ReadAsync yields null or SecretPayload.Value == null - e.g. the underlying value was deleted from the store, an environment/configuration-backed store has no value bound for the key, or a read failure was swallowed into a null result.
Common situations: Configuration-backed stores where the referenced configuration key was removed or renamed, external stores where the value was deleted out-of-band, or stores that cannot decrypt a payload written by a different key/tenant.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Secret ' ' was not found.
- Secret type ' ' does not support store ' '.
- A configuration key is required.
- A managed secret writer returned the live secret reference…
- A secret named ' ' already exists.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/435e1637b0867697.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretManager.cs:161
{
return new SecretTestResponse { Succeeded = false, Error = e.Message };
}
}
public async Task<SecretPayload> ResolvePayloadAsync(string name, CancellationToken cancellationToken = default)
{
var secret = await GetExistingAsync(name, cancellationToken);
return await ResolvePayloadAsync(secret, cancellationToken);
}
public async Task<SecretPayload> ResolvePayloadAsync(Secret secret, CancellationToken cancellationToken = default)
{
var version = GetLatestActiveVersion(secret);
var store = storeRegistry.Get(secret.StoreName);
var payload = await store.ReadAsync(secret, version, cancellationToken);
if (payload?.Value == null)
throw new InvalidOperationException($"Secret '{secret.Name}' could not be resolved.");
return payload;
}
private async Task<Secret> CreateSecretAsync(CreateSecretRequest request, CancellationToken cancellationToken)
{
var typeProvider = typeRegistry.Get(request.TypeName);
var store = storeRegistry.Get(request.StoreName);
EnsureCanWrite(store);
if (!typeProvider.Descriptor.SupportedStoreNames.Contains(store.Name, StringComparer.OrdinalIgnoreCase))
throw new InvalidOperationException($"Secret type '{request.TypeName}' does not support store '{request.StoreName}'.");
if (!typeProvider.Validate(request, out var error))
throw new InvalidOperationException(error);
var secret = new Secret
{View on GitHub (pinned to fe9217bdfa)