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
- Wrap the secret name in a SecretReference when building the expression: new Expression(...){ Value = new SecretReference { Name = "my-secret" } }.
- Use the provided secret expression factory/helper rather than constructing Expression objects manually.
- Check how the workflow definition was serialized; ensure the expression value round-trips as a SecretReference.
- 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
- Always create secret expressions via the dedicated factory methods.
- Unit-test expression serialization round-trips in custom activities.
- Never put raw strings in Secret-typed expressions.
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
- The configured secret binding is incompatible with the…
- Secret expression reference must specify a secret name.
- Expected a string metadata value.
- Secret ' ' is not compatible with required type ' '.
- Cannot deserialize to .
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)