elsa-workflows / elsa-workflows/elsa-core
Elsa 3.4: SetVariable activity as expression type Python and array variables lead to workflow instance crash
- Dominant language
- C#
- Stars
- 7.9k
- Forks
- 1.5k
- Avg merge
- 15h 22m
- Merged PRs (30d)
- 114
Description
## Description
```
{
"activityId": "SetVariable",
"activityType": "Elsa.SetVariable",
"message": "invalid syntax. Perhaps you forgot a comma? (, line 19)",
"exception": {
"type": "Python.Runtime.PythonException, Python.Runtime, Version=3.1.0.0, Culture=neutral, PublicKeyToken=5000fea6cba702dd",
"message": "invalid syntax. Perhaps you forgot a comma? (, line 19)",
"stackTrace": " at Python.Runtime.PythonException.ThrowLastAsClrException()\n at Python.Runtime.PythonException.ThrowIfIsNull(NewReference& ob)\n at Python.Runtime.PyModule.Exec(String code, BorrowedReference _globals, BorrowedReference _locals)\n at Python.Runtime.PyModule.Exec(String code, PyDict locals)\n at Elsa.Python.Notifications.EvaluatingPython.AppendScript(String script)\n at Paragon.LowCode.Workflows.Elsa3.WorkflowEngine.ElsaEngine.Handlers.GenerateWorkflowVariableAccessors.HandleAsync(EvaluatingPython notification, CancellationToken cancellationToken) in /_/src/Paragon.LowCode.Workflows.Elsa3.WorkflowEngine.ElsaEngine/Handlers/GenerateWorkflowVariableAccessors.cs:line 56\n at Paragon.LowCode.Workflows.Elsa3.WorkflowEngine.ElsaEngine.Services.PythonNetPythonEvaluator.EvaluateAsync(String expression, Type returnType, ExpressionExecutionContext context, CancellationToken cancellationToken) in /_/src/Paragon.LowCode.Workflows.Elsa3.WorkflowEngine.ElsaEngine/Services/PythonNetPythonEvaluator.cs:line 45\n at Elsa.Python.Expressions.PythonExpressionHandler.EvaluateAsync(Expression expression, Type returnType, ExpressionExecutionContext context, ExpressionEvaluatorOptions options)\n at Elsa.Expressions.Services.ExpressionEvaluator.EvaluateAsync(Expression expression, Type returnType, ExpressionExecutionContext context, ExpressionEvaluatorOptions options)\n at Elsa.Extensions.ActivityExecutionContextExtensions.EvaluateInputPropertyAsync(ActivityExecutionContext context, ActivityDescriptor activityDescriptor, InputDescriptor inputDescriptor)\n at Elsa.Extensions.ActivityExecutionContextExtensions.EvaluateInputPropertiesAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Middleware.Activities.DefaultActivityInvokerMiddleware.EvaluateInputPropertiesAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Middleware.Activities.DefaultActivityInvokerMiddleware.InvokeAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Runtime.Middleware.EvaluateLogPersistenceModesMiddleware.InvokeAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Middleware.Activities.NotificationPublishingMiddleware.InvokeAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Middleware.Activities.ExecutionLogMiddleware.InvokeAsync(ActivityExecutionContext context)\n at Elsa.Workflows.Middleware.Activities.ExceptionHandlingMiddleware.InvokeAsync(ActivityExecutionContext context)"
}
```
## Steps to Reproduce
Create workflow with two variables (TypeName = String, first IsArray = false, second IsArray = true) and one activity (type = SetVariable, value expression type = Python), then publish and execute - fail
Api input
```
{
Name = workflowKey,
Description = "Test workflow",
Variables =
[
new ()
{
Id = "string",
Name = "MyString",
TypeName = "String",
IsArray = false,
Value = 0,
StorageDriverTypeName = "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
},
new ()
{
Id = "string_array",
Name = "MyArray",
TypeName = "String",
IsArray = true,
Value = 0,
StorageDriverTypeName = "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core",
},
],
StringData = $$$"""
{
"id": "Elsa3Server1",
"type": "Elsa.Flowchart",
"activities": [
{
"id": "SetVariable",
"type": "Elsa.SetVariable",
"variable": {
"id": "string",
"name": "String",
"typeName": "String",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Object",
"expression": {
"type": "Python",
"value": "'Hello world!'"
}
}
}
]
}
""",
}
```
Import from dashboard
```
{
"$schema": "https://elsaworkflows.io/schemas/workflow-definition/v3.0.0/schema.json",
"id": "9bc379491faa72a7",
"definitionId": "378df39d464e4aae8078282daf89ad46",
"tenantId": "cb4b6bd3-6f3f-4e09-adf1-9f3449102fd8",
"name": "TMP_WORKFLOW",
"createdAt": "2025-07-29T12:24:21.142388+00:00",
"version": 4,
"variables": [
{
"id": "d57429a7d649be59",
"name": "strVar",
"typeName": "String",
"isArray": false,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
{
"id": "bf1e7facfd0d0c96",
"name": "varArray",
"typeName": "String",
"isArray": true,
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
}
],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isSystem": false,
"isLatest": true,
"isPublished": false,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"id": "Flowchart1",
"nodeId": "Workflow1:Flowchart1",
"name": "Flowchart1",
"type": "Elsa.Flowchart",
"version": 1,
"customProperties": {
"notFoundConnections": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {},
"activities": [
{
"variable": {
"id": "d57429a7d649be59",
"name": "strVar",
"typeName": "String",
"storageDriverTypeName": "Elsa.Workflows.Services.WorkflowStorageDriver, Elsa.Workflows.Core"
},
"value": {
"typeName": "Object",
"expression": {
"type": "Python",
"value": "'Hello world'"
}
},
"id": "a9e62d79a5d0d2a5",
"nodeId": "Workflow1:Flowchart1:a9e62d79a5d0d2a5",
"name": "SetVariable1",
"type": "Elsa.SetVariable",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": -211.17501831054688,
"y": -67.60000610351562
},
"size": {
"width": 152.65625,
"height": 50
}
}
}
}
],
"variables": [],
"connections": []
}
}
```
## Expected Behavior
Workflow Finished
## Actual Behavior
Workflow Failed
## Screenshots
## Environment
Elsa Version="3.4.0"
## Troubleshooting Attempts
Problem in Elsa.Python.Handlers.GenerateWorkflowVariableAccessors,
line 40, when using invalid syntaxes `return self.execution_context.GetVariable[System.String[]]('MyArray')`
Python does not support calls like `GetVariable[System.String[]]()` - this is C# or C++ template syntax and is not valid in Python.
Solution - Use GetVariable(name) without specifying the type (if PyObject is returned)
**When I rewrite code block - workflow is finished successfully**
```
public Task HandleAsync(EvaluatingPython notification, CancellationToken cancellationToken)
{
var expressionExecutionContext = notification.Context;
var variables = expressionExecutionContext.GetVariablesInScope().ToList();
var sb = new StringBuilder();
sb.AppendLine("class WorkflowVariablesProxy:");
sb.AppendLine(" def __init__(self, execution_context):");
sb.AppendLine(" self.execution_context = execution_context");
sb.AppendLine();
sb.AppendLine(" def get(self, name):");
sb.AppendLine(" return self.execution_context.GetVariable(name)");
sb.AppendLine();
sb.AppendLine(" def set(self, name, value):");
sb.AppendLine(" self.execution_context.SetVariable(name, value)");
sb.AppendLine();
foreach (var variable in variables)
{
logger.LogInformation("Process variable name {variableName}", variable.Name);
var variableName = variable.Name;
sb.AppendLine($" @property");
sb.AppendLine($" def {variableName}(self):");
sb.AppendLine($" return self.execution_context.GetVariable('{variableName}')");
sb.AppendLine($" @{variableName}.setter");
sb.AppendLine($" def {variableName}(self, value):");
sb.AppendLine($" self.execution_context.SetVariable('{variableName}', value)");
}
sb.AppendLine();
sb.AppendLine("variables = WorkflowVariablesProxy(execution_context);");
logger.LogInformation("Python code {pythonCode}", sb.ToString());
notification.AppendScript(sb.ToString());
return Task.CompletedTask;
}
```
**Python script tests not found in repo**
Contributor guide
Assessment
This issue has not been assessed yet.