elsa-workflows/elsa-core · error · InvalidOperationException

Secret expression value must be a SecretReference.

Error message

Secret expression value must be a SecretReference.

What it means

SecretExpressionHandler evaluates a 'Secret' expression by expecting Expression.Value to be a SecretReference. If the expression was built with some other value type (a string, raw object, etc.), it throws this InvalidOperationException immediately. The expression payload, not the runtime input, is what is validated.

Solutions

  1. Wrap the secret name in a SecretReference when building the expression: new Expression(...){ Value = new SecretReference { Name = "my-secret" } }.
  2. Use the provided secret expression factory/helper rather than constructing Expression objects manually.
  3. Check how the workflow definition was serialized; ensure the expression value round-trips as a SecretReference.
  4. Verify the activity or designer producing the expression emits the correct expression type/value pair.

Example fix

// before
var expr = new Expression("Secret", "my-secret");

// after
var expr = new Expression("Secret", new SecretReference { Name = "my-secret" });
Defensive patterns

Strategy: type-guard

Validate before calling

if (expression.Value is not SecretReference) throw new InvalidOperationException("Secret expression requires a SecretReference value.");

Type guard

static bool IsSecretExpression(Expression e) => e.Value is SecretReference { Name: not null and not "" };

Try / catch

try { var value = await handler.EvaluateAsync(expression, returnType, context, options); }
catch (InvalidOperationException ex) when (ex.Message.Contains("SecretReference")) { /* fix expression construction or surface config error */ }

Prevention

When it happens

Trigger: Constructing an Expression for the secret expression type with Value set to something other than a SecretReference (e.g. a plain string secret name or a deserialized/round-tripped expression that lost its typed value).

Common situations: Hand-building expressions in code instead of using the Secret expression factory; persisting workflow definitions that round-trip expression values as JSON losing the typed SecretReference; copying expression snippets from older workflow formats.

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/1271fad2682ce010. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Secrets/Expressions/SecretExpressionHandler.cs:16

using Elsa.Expressions.Contracts;
using Elsa.Expressions.Helpers;
using Elsa.Expressions.Models;

namespace Elsa.Secrets.Expressions;

/// <summary>
/// Resolves Secret expressions through the configured secret resolver.
/// </summary>
public class SecretExpressionHandler(ISecretResolver secretResolver, IWellKnownTypeRegistry wellKnownTypeRegistry) : IExpressionHandler
{
    /// <inheritdoc />
    public async ValueTask<object?> EvaluateAsync(Expression expression, Type returnType, ExpressionExecutionContext context, ExpressionEvaluatorOptions options)
    {
        if (expression.Value is not SecretReference reference)
            throw new InvalidOperationException("Secret expression value must be a SecretReference.");

        if (string.IsNullOrWhiteSpace(reference.Name))
            throw new InvalidOperationException("Secret expression reference must specify a secret name.");

        var value = await secretResolver.ResolveAsync(reference, context.CancellationToken);
        return value.ConvertTo(returnType, new ObjectConverterOptions(WellKnownTypeRegistry: wellKnownTypeRegistry));
    }
}

View on GitHub (pinned to fe9217bdfa)