elsa-workflows/elsa-core · error · InvalidOperationException

C# workflow expression execution is disabled. Set…

Error message

C# workflow expression execution is disabled. Set CSharpOptions.AllowHostCodeExecution to true only for trusted workflow authors; Roslyn scripting is not a sandbox.

What it means

The C# expression evaluator intentionally refuses to run Roslyn-scripted workflow expressions unless host code execution is explicitly enabled via CSharpOptions.AllowHostCodeExecution. Because Roslyn scripting is not a sandbox, enabling it lets workflow authors execute arbitrary code on the host, so the default is disabled and this InvalidOperationException is thrown when a C# expression requiring script execution is evaluated.

Solutions

  1. Set CSharpOptions.AllowHostCodeExecution = true in host configuration, ONLY if workflow authors are fully trusted
  2. Rewrite the workflow expression in a sandboxed-safe language such as JavaScript or a restricted C# expression mode
  3. Move the needed logic into a custom activity or C# method exposed via allowed APIs instead of raw scripting
  4. Confirm which expression in the workflow requires scripting and remove or replace it

Example fix

// before
services.AddCSharpExpressions(); // AllowHostCodeExecution defaults to false
// after
services.AddCSharpExpressions(options => options.AllowHostCodeExecution = true); // trusted authors only
Defensive patterns

Strategy: validation

Validate before calling

// host-side guard before evaluating C# expressions
var opts = serviceProvider.GetRequiredService<IOptions<CSharpOptions>>().Value;
if (!opts.AllowHostCodeExecution)
    throw new InvalidOperationException("C# scripting is disabled; set CSharpOptions.AllowHostCodeExecution=true only for trusted authors.");

Try / catch

try { result = await evaluator.EvaluateAsync(expression, ...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("AllowHostCodeExecution"))
{
    logger.LogWarning("C# script execution blocked: enable AllowHostCodeExecution if authors are trusted");
    throw;
}

Prevention

When it happens

Trigger: Evaluating a C# expression that requires scripting (EvaluateAsync with script options) while CSharpOptions.AllowHostCodeExecution is false (the default) — e.g. a workflow using `(C#) ...` expressions with host-level scripting features.

Common situations: Deploying workflows using C# script expressions to a host that never opted in; upgrading Elsa where the safety default flipped to disabled; security-hardened production environments rejecting script execution.

Related errors


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

Appendix: source

Thrown at src/modules/Elsa.Expressions.CSharp/Services/CSharpEvaluator.cs:38

/// <remarks>
/// Initializes a new instance of the <see cref="CSharpEvaluator"/> class.
/// </remarks>
public class CSharpEvaluator(INotificationSender notificationSender, IOptions<CSharpOptions> scriptOptions, IMemoryCache memoryCache) : ICSharpEvaluator
{
    private readonly CSharpOptions _csharpOptions = scriptOptions.Value;

    /// <inheritdoc />
    public async Task<object?> EvaluateAsync(
        string expression,
        Type returnType,
        ExpressionExecutionContext context,
        ExpressionEvaluatorOptions options,
        Func<ScriptOptions, ScriptOptions>? configureScriptOptions = default,
        Func<Script<object>, Script<object>>? configureScript = default,
        CancellationToken cancellationToken = default)
    {
        if (!_csharpOptions.AllowHostCodeExecution)
            throw new InvalidOperationException("C# workflow expression execution is disabled. Set CSharpOptions.AllowHostCodeExecution to true only for trusted workflow authors; Roslyn scripting is not a sandbox.");

        var scriptOptions = ScriptOptions.Default.WithOptimizationLevel(OptimizationLevel.Release);

        if (configureScriptOptions != null)
            scriptOptions = configureScriptOptions(scriptOptions);

        var globals = new Globals(context, options.Arguments);
        var script = CSharpScript.Create("", scriptOptions, typeof(Globals));

        if (configureScript != null)
            script = configureScript(script);

        var notification = new EvaluatingCSharp(options, script, scriptOptions, context);
        await notificationSender.SendAsync(notification, cancellationToken);
        scriptOptions = notification.ScriptOptions;
        script = notification.Script.ContinueWith(expression, scriptOptions);
        var runner = GetCompiledScript(script);
        return await runner(globals, cancellationToken: cancellationToken);

View on GitHub (pinned to fe9217bdfa)