elsa-workflows/elsa-core · error · InvalidOperationException
Python.NET workflow expression execution is disabled. Set…
Error message
Python.NET workflow expression execution is disabled. Set PythonOptions.AllowHostCodeExecution to true only for trusted workflow authors; Python.NET is not a sandbox.
What it means
The Python.NET evaluator refuses to execute workflow expressions unless PythonOptions.AllowHostCodeExecution is explicitly true, because Python.NET gives scripts full host access and is not a sandbox. The throw is a security guard added by Elsa to prevent untrusted workflow authors from executing arbitrary host code.
Solutions
- Set PythonOptions.AllowHostCodeExecution to true only if workflow authors are fully trusted: builder.Services.Configure<PythonOptions>(o => o.AllowHostCodeExecution = true;)
- If workflows must not run privileged code, rewrite the expressions in a sandboxed language (JavaScript with sandboxing or C#) instead of enabling the flag
- Confirm the configuration binding actually reaches the options (e.g. configuration section key casing) so the flag is true at evaluation time
Example fix
// before builder.Services.AddPython(); // after (trusted authors only) builder.Services.AddPython(); builder.Services.Configure<PythonOptions>(o => o.AllowHostCodeExecution = true);
Defensive patterns
Strategy: validation
Validate before calling
// at startup, fail fast if the flag is required but unset
if (usesPythonExpressions && !pythonOptions.AllowHostCodeExecution)
throw new InvalidOperationException("Enable PythonOptions.AllowHostCodeExecution for trusted authors."); Try / catch
try { await evaluator.EvaluateAsync(expr, typeof(object), ctx, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("AllowHostCodeExecution"))
{ logger.LogWarning("Python execution disabled; reconfigure options."); } Prevention
- Set AllowHostCodeExecution = true only in trusted-author environments
- Document the security implications for operators
- Prefer sandboxed JS/C# expressions for untrusted authors
When it happens
Trigger: Evaluating any Python expression via PythonNetPythonEvaluator.EvaluateAsync while PythonOptions.AllowHostCodeExecution is false/unset (the safe default).
Common situations: Deploying an app that uses Python expressions without opting into host code execution, or upgrading Elsa to a version that introduced this opt-in flag and existing workflows stop running.
Related errors
- C# workflow expression execution is disabled. Set…
- Register with configured before calling , or call with a…
- The console log provider registration is invalid.
- Access denied.
- OpenTelemetry gRPC ingestion is enabled, but no gRPC…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/b601a7401dad0263.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Expressions.Python/Services/PythonNetPythonEvaluator.cs:43
/// </summary>
public PythonNetPythonEvaluator(INotificationSender notificationSender) : this(notificationSender, Microsoft.Extensions.Options.Options.Create(new PythonOptions()))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PythonNetPythonEvaluator"/> class.
/// </summary>
public PythonNetPythonEvaluator(INotificationSender notificationSender, IOptions<PythonOptions> options)
{
_notificationSender = notificationSender;
_options = options;
}
/// <inheritdoc />
public async Task<object?> EvaluateAsync(string expression, Type returnType, ExpressionExecutionContext context, CancellationToken cancellationToken = default)
{
if (!_options.Value.AllowHostCodeExecution)
throw new InvalidOperationException("Python.NET workflow expression execution is disabled. Set PythonOptions.AllowHostCodeExecution to true only for trusted workflow authors; Python.NET is not a sandbox.");
using var gil = Py.GIL();
using var scope = Py.CreateScope();
var notification = new EvaluatingPython(scope, context);
scope.Import("System");
// Add globals.
scope.Set("execution_context", new ExecutionContextProxy(context));
scope.Set("input", new InputProxy(context));
scope.Set("output", new OutputProxy(context));
scope.Set("outcome", new OutcomeProxy(context));
await _notificationSender.SendAsync(notification, cancellationToken);
var wrappedScript = WrapInExecuteScriptFunction(expression);
scope.Exec(wrappedScript);
var result = scope.Get<object>(ReturnVarName);
return result.ConvertTo(returnType);View on GitHub (pinned to fe9217bdfa)