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

  1. Update the reference TypeName to match the stored secret's TypeName.
  2. Recreate/update the secret with the expected TypeName.
  3. Remove TypeName from the reference if type enforcement is not required.
  4. 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

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


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)