elsa-workflows/elsa-core · error · InvalidOperationException
Secret ' ' is not compatible with required type ' '.
Error message
Secret '{reference.Name}' is not compatible with required type '{reference.TypeName}'. What it means
ResolveAsync optionally validates that the secret's TypeName matches the SecretReference.TypeName (case-insensitive) and throws InvalidOperationException on mismatch. This guards against binding a secret to code expecting a different secret type/schema. It fires only when a TypeName was specified on the reference.
Solutions
- Update the reference TypeName to match the stored secret's TypeName.
- Recreate/update the secret with the expected TypeName.
- Remove TypeName from the reference if type enforcement is not required.
- Fix migrations/creation code so TypeName is persisted.
Example fix
// before
var value = await resolver.ResolveAsync(new SecretReference("ApiKey", typeName: "HttpApiKey"));
// after
var value = await resolver.ResolveAsync(new SecretReference("ApiKey", typeName: "ApiKey")); // matches secret.TypeName Defensive patterns
Strategy: validation
Validate before calling
var secret = await secretManager.GetAsync(reference.Name, ct);
if (secret is not null && !string.IsNullOrEmpty(reference.TypeName) &&
!string.Equals(secret.TypeName, reference.TypeName, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException($"Type mismatch for secret '{reference.Name}'."); Type guard
bool TypeMatches(Secret? s, string? expected) =>
string.IsNullOrEmpty(expected) || string.Equals(s?.TypeName, expected, StringComparison.OrdinalIgnoreCase); Try / catch
try { var value = await resolver.ResolveAsync(reference, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not compatible with required type")) { logger.LogError("Secret {Name} has wrong type: {Msg}", reference.Name, ex.Message); throw; } Prevention
- Always set TypeName when creating typed secrets
- Keep type names in shared constants
- Validate type after migrations/imports
When it happens
Trigger: Resolving a SecretReference with TypeName set (e.g. 'ConnectionString') while the stored secret's TypeName is different or null.
Common situations: Secret recreated without its type metadata; reference copied from another secret; type naming changed between versions; migration dropped TypeName.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- The secret field name must contain a letter or digit.
- The configured secret binding is incompatible with the…
- Configuration connection
- The configured secret binding is invalid.
- Secret expression value must be a SecretReference.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/c4df69567b647484.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretResolver.cs:14
namespace Elsa.Secrets.Services;
public class DefaultSecretResolver(ISecretManager secretManager) : ISecretResolver
{
public Task<string> ResolveAsync(string name, CancellationToken cancellationToken = default) => ResolveAsync(new SecretReference(name), cancellationToken);
public async Task<string> ResolveAsync(SecretReference reference, CancellationToken cancellationToken = default)
{
var secret = await secretManager.GetAsync(reference.Name, cancellationToken);
if (secret == null)
throw new InvalidOperationException($"Secret '{reference.Name}' was not found.");
if (!string.IsNullOrWhiteSpace(reference.TypeName) && !string.Equals(secret.TypeName, reference.TypeName, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException($"Secret '{reference.Name}' is not compatible with required type '{reference.TypeName}'.");
if (!string.IsNullOrWhiteSpace(reference.Scope) && !string.Equals(secret.Scope, reference.Scope, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException($"Secret '{reference.Name}' is not compatible with required scope '{reference.Scope}'.");
var payload = await secretManager.ResolvePayloadAsync(secret, cancellationToken);
return payload.Value!;
}
}
View on GitHub (pinned to fe9217bdfa)