conductor icon indicating copy to clipboard operation
conductor copied to clipboard

No evaluator registered for type: graaljs

Open albert-cg opened this issue 8 months ago • 4 comments

Describe the bug Error executing switch task with graaljs

This example is taken from https://orkes.io/content/reference-docs/operators/switch

Details Conductor version: 3.21.12 and 3.21.13 Persistence implementation: Postgres Queue implementation: Postgres Lock: N/A Workflow definition: test_graal_js

  "createTime": 1744797500201,
  "updateTime": 0,
  "name": "test_graaljs",
  "description": "Edit or extend this sample workflow. Set the workflow name to get started",
  "version": 1,
  "tasks": [
    {
      "name": "switch",
      "taskReferenceName": "switch_ref",
      "inputParameters": {
        "switchCaseValue": "${workflow.input.type}"
      },
      "type": "SWITCH",
      "decisionCases": {
        "apples": [
          {
            "name": "notify_apple_task",
            "taskReferenceName": "notify_apple_task",
            "inputParameters": {
              "http_request": {
                "uri": "http://app.domain/api/communication",
                "method": "POST",
                "body": {
                  "subject": "Notification Apples"
                }
              }
            },
            "type": "HTTP",
            "decisionCases": {},
            "defaultCase": [],
            "forkTasks": [],
            "startDelay": 0,
            "joinOn": [],
            "optional": false,
            "defaultExclusiveJoinTask": [],
            "asyncComplete": false,
            "loopOver": [],
            "onStateChange": {},
            "permissive": false
          }
        ],
        "tomatoes": [
          {
            "name": "do_tomatoes_task",
            "taskReferenceName": "do_tomatoes_task",
            "inputParameters": {
              "http_request": {
                "uri": "http://app.domain/api/tomatoes",
                "method": "POST",
                "body": {
                  "subject": "Task tomatoes"
                }
              }
            },
            "type": "HTTP",
            "decisionCases": {},
            "defaultCase": [],
            "forkTasks": [],
            "startDelay": 0,
            "joinOn": [],
            "optional": false,
            "defaultExclusiveJoinTask": [],
            "asyncComplete": false,
            "loopOver": [],
            "onStateChange": {},
            "permissive": false
          }
        ]
      },
      "defaultCase": [],
      "forkTasks": [],
      "startDelay": 0,
      "joinOn": [],
      "optional": false,
      "defaultExclusiveJoinTask": [],
      "asyncComplete": false,
      "loopOver": [],
      "evaluatorType": "graaljs",
      "expression": "(function () {\n    switch ($.switchCaseValue) {\n      case \"1\":\n        return \"apple\";\n      case \"2\":\n        return \"tomatoes\";\n      case \"3\":\n        return \"oranges\"\n    }\n  }())",
      "onStateChange": {},
      "permissive": false
    }
  ],
  "inputParameters": [],
  "outputParameters": {},
  "schemaVersion": 2,
  "restartable": true,
  "workflowStatusListenerEnabled": false,
  "ownerEmail": "[email protected]",
  "timeoutPolicy": "ALERT_ONLY",
  "timeoutSeconds": 0,
  "variables": {},
  "inputTemplate": {},
  "enforceSchema": true
}

Task definition: N/A Event handler definition: N/A

Workarround I made:

  1. Inline task processing input vars and generating output var
  2. Switch type param-value with the previous output

To Reproduce Steps to reproduce the behavior:

  1. Launch workflow: test_graaljs
  2. With and without input json
  3. See instant failed status with message: No evaluator registered for type: graaljs

Screenshots Image Image

Additional context Generated JSON

{
  "ownerApp": "",
  "createTime": 1744797675108,
  "updateTime": 1744797675127,
  "status": "FAILED",
  "endTime": 1744797675127,
  "workflowId": "0ecd7169-b091-42e5-96af-6dbef5bb1a5a",
  "tasks": [],
  "input": {
    "type": "apple"
  },
  "output": {},
  "reasonForIncompletion": "No evaluator registered for type: graaljs",
  "taskToDomain": {},
  "failedReferenceTaskNames": [],
  "workflowDefinition": {
    "createTime": 1744797500201,
    "updateTime": 0,
    "name": "test_graaljs",
    "description": "Edit or extend this sample workflow. Set the workflow name to get started",
    "version": 1,
    "tasks": [
      {
        "name": "switch",
        "taskReferenceName": "switch_ref",
        "inputParameters": {
          "switchCaseValue": "${workflow.input.type}"
        },
        "type": "SWITCH",
        "decisionCases": {
          "apples": [
            {
              "name": "notify_apple_task",
              "taskReferenceName": "notify_apple_task",
              "inputParameters": {
                "http_request": {
                  "uri": "http://app.domain/api/communication",
                  "method": "POST",
                  "body": {
                    "subject": "Notification Apples"
                  }
                }
              },
              "type": "HTTP",
              "decisionCases": {},
              "defaultCase": [],
              "forkTasks": [],
              "startDelay": 0,
              "joinOn": [],
              "optional": false,
              "defaultExclusiveJoinTask": [],
              "asyncComplete": false,
              "loopOver": [],
              "onStateChange": {},
              "permissive": false
            }
          ],
          "tomatoes": [
            {
              "name": "do_tomatoes_task",
              "taskReferenceName": "do_tomatoes_task",
              "inputParameters": {
                "http_request": {
                  "uri": "http://app.domain/api/tomatoes",
                  "method": "POST",
                  "body": {
                    "subject": "Task tomatoes"
                  }
                }
              },
              "type": "HTTP",
              "decisionCases": {},
              "defaultCase": [],
              "forkTasks": [],
              "startDelay": 0,
              "joinOn": [],
              "optional": false,
              "defaultExclusiveJoinTask": [],
              "asyncComplete": false,
              "loopOver": [],
              "onStateChange": {},
              "permissive": false
            }
          ]
        },
        "defaultCase": [],
        "forkTasks": [],
        "startDelay": 0,
        "joinOn": [],
        "optional": false,
        "defaultExclusiveJoinTask": [],
        "asyncComplete": false,
        "loopOver": [],
        "evaluatorType": "graaljs",
        "expression": "(function () {\n    switch ($.switchCaseValue) {\n      case \"1\":\n        return \"apple\";\n      case \"2\":\n        return \"tomatoes\";\n      case \"3\":\n        return \"oranges\"\n    }\n  }())",
        "onStateChange": {},
        "permissive": false
      }
    ],
    "inputParameters": [],
    "outputParameters": {},
    "schemaVersion": 2,
    "restartable": true,
    "workflowStatusListenerEnabled": false,
    "ownerEmail": "[email protected]",
    "timeoutPolicy": "ALERT_ONLY",
    "timeoutSeconds": 0,
    "variables": {},
    "inputTemplate": {},
    "enforceSchema": true
  },
  "priority": 0,
  "variables": {},
  "lastRetriedTime": 0,
  "failedTaskNames": [],
  "history": [],
  "rateLimited": false,
  "workflowName": "test_graaljs",
  "workflowVersion": 1,
  "startTime": 1744797675108
}

albert-cg avatar Apr 16 '25 10:04 albert-cg

In conductor OSS it seems that in order to be evaluated as JavaScript the evaluatorType is javascript and not graaljs https://docs.conductor-oss.org/documentation/configuration/workflowdef/operators/switch-task.html#evaluator-types-and-expression

JCHacking avatar May 12 '25 19:05 JCHacking

Accordign to conductor-python sdk switch task between lines 43-41, the only accepted values are:

  • value-param
  • graaljs

albert-cg avatar May 14 '25 14:05 albert-cg

Yes, but you can see that in the Enum is also the JavaScript value (https://github.com/conductor-sdk/conductor-python/blob/main/src/conductor/client/workflow/task/switch_task.py#L13), it is the bad thing about Conductor that you have Conductor OSS and Orker, and they are not exactly the same...

Here are all the expression evaludator included in condutor. https://github.com/conductor-oss/conductor/tree/main/core/src/main/java/com/netflix/conductor/core/execution/evaluators

I don't see any graaljs, I only see javascript. https://github.com/conductor-oss/conductor/blob/main/core/src/main/java/com/netflix/conductor/core/execution/evaluators/JavascriptEvaluator.java#L27

My theory is that Orkes includes an extra expresssion evaludator graaljs, which the open source version does not have. And the python SDK is bugged as it is only supported in this aspect by Orkes. In this commit it was changed: https://github.com/conductor-sdk/conductor-python/commit/193564f3393ec0c4f799af32a56fb3bc5ce9057b

JCHacking avatar May 14 '25 15:05 JCHacking

Good news! We're actively working on migrating from Nashorn to GraalJS, which should resolve this issue.

The error you're seeing ("No evaluator registered for type: graaljs") is because the OSS version currently only has these evaluators registered:

  • "javascript" (uses deprecated Nashorn)
  • "value-param"
  • "python"

The GraalJS migration is tracked in issue #617 and is a high-priority fix. This migration will:

  • Replace the broken Nashorn engine with modern GraalJS
  • Add timeout protection, console bridge support, and security features
  • Enable JavaScript evaluation on modern Java (17, 21+)
  • Port the implementation from Orkes Enterprise to OSS

Migration is expected very soon. We're just finalizing the evaluator naming convention to ensure OSS-Enterprise parity (see discussion in #617).

In the meantime, your workaround is the right approach. Once the migration is complete, you'll be able to use "evaluatorType": "graaljs" (or "javascript" depending on the final naming decision) directly in your SWITCH tasks.

Thank you for reporting this issue!

nthmost-orkes avatar Oct 22 '25 03:10 nthmost-orkes