elsa-workflows/elsa-core · error · InvalidOperationException

Secret ' ' is not compatible with required scope ' '.

Error message

Secret '{reference.Name}' is not compatible with required scope '{reference.Scope}'.

What it means

ResolveAsync optionally validates that the secret's Scope matches the SecretReference.Scope (case-insensitive) and throws InvalidOperationException on mismatch. This enforces that secrets are only consumed within their intended scope (environment/tenant/module). Fires only when the reference specifies a Scope.

Solutions

  1. Align the reference Scope with the secret's actual Scope.
  2. Update the secret's Scope to the expected value if appropriate.
  3. Create a correctly scoped secret for the target environment/tenant.
  4. Remove Scope from the reference if cross-scope access is intended.

Example fix

// before
var value = await resolver.ResolveAsync(new SecretReference("SftpPassword", scope: "Production"));
// after
var value = await resolver.ResolveAsync(new SecretReference("SftpPassword", scope: "Staging")); // matches secret.Scope
Defensive patterns

Strategy: validation

Validate before calling

var secret = await secretManager.GetAsync(reference.Name, ct);
if (secret is not null && !string.IsNullOrEmpty(reference.Scope) &&
    !string.Equals(secret.Scope, reference.Scope, StringComparison.OrdinalIgnoreCase))
    throw new InvalidOperationException($"Scope mismatch for secret '{reference.Name}'.");

Type guard

bool ScopeMatches(Secret? s, string? expected) =>
    string.IsNullOrEmpty(expected) || string.Equals(s?.Scope, expected, StringComparison.OrdinalIgnoreCase);

Try / catch

try { var value = await resolver.ResolveAsync(reference, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not compatible with required scope")) { logger.LogError("Secret {Name} scope mismatch: {Msg}", reference.Name, ex.Message); throw; }

Prevention

When it happens

Trigger: Resolving a SecretReference with Scope set while the stored secret's Scope differs (or is null), e.g. reference scoped to 'Production' but secret scoped to 'Staging'.

Common situations: Promoting configuration between environments where scope labels differ; multi-tenant setups with per-tenant scoped secrets; scope renamed during refactoring.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretResolver.cs:17

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)