conductor-oss/conductor · error · NonTransientException

Script not evaluated within %d seconds, interrupted.

Error message

Script not evaluated within %d seconds, interrupted.

What it means

Thrown by ScriptEvaluator when a GraalVM JavaScript expression does not finish within maxExecutionTimeSeconds (default 4s) on the context-pool code path (CONDUCTOR_SCRIPT_CONTEXT_POOL_ENABLED=true). The evaluator submits the eval to an executor and calls Future.get with the timeout; a TimeoutException is caught, the polyglot Context is interrupted, and a NonTransientException is raised. NonTransient tells the workflow engine that retrying the same script will not help, so the task is not retried automatically.

Source

Thrown at core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java:332

        final Source source = getSource(script);

        if (contextPoolEnabled) {
            // Context pool implementation
            ScriptExecutionContext scriptContext = null;
            try {
                scriptContext = contextPool.take();
                final ScriptExecutionContext finalScriptContext = scriptContext;
                finalScriptContext.prepareBindings(input, console);
                Future<Value> futureResult =
                        executorService.submit(() -> finalScriptContext.getContext().eval(source));
                Value value =
                        futureResult.get(maxExecutionTimeSeconds.getSeconds(), TimeUnit.SECONDS);
                return getObject(value);
            } catch (TimeoutException e) {
                if (scriptContext != null) {
                    interrupt(scriptContext.getContext());
                }
                throw new NonTransientException(
                        String.format(
                                "Script not evaluated within %d seconds, interrupted.",
                                maxExecutionTimeSeconds.getSeconds()));
            } catch (ExecutionException ee) {
                handlePolyglotException(ee);
                return null;
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new NonTransientException("Script execution interrupted: " + ie.getMessage());
            } finally {
                if (scriptContext != null) {
                    scriptContext.clearBindings();
                    if (!contextPool.offer(scriptContext)) {
                        scriptContext.getContext().close();
                        LOGGER.warn(
                                "ScriptExecutionContext pool is full, context closed and not returned to pool.");
                    }
                }

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the failing script for loops/recursion/blocking calls and bound it algorithmically.
  2. Raise the budget via `conductor.systemTaskEvalTimeoutSeconds` (or the ScriptEvaluator initializer maxSeconds arg) only if the script is genuinely O(n) over large input.
  3. Refactor the logic out of inline JS into a dedicated worker task for long-running computation.
  4. Keep the context pool disabled (the default) unless you fully control every script, since pooled contexts can change latency characteristics.
  5. Catch NonTransientException at the task boundary and fail the task explicitly with a clear reason instead of relying on the generic message.

Example fix

// before
var i = 0; while (true) { i++; }  // unbounded

// after
var i = 0, max = 1_000_000;
while (i < max) { i++; }  // bounded
Defensive patterns

Strategy: validation

Validate before calling

// Before exposing a script, sanity-check it does not contain obvious infinite loops.
// Pre-flight: run it offline with the same maxExecutionTimeSeconds budget.
Duration budget = Duration.ofSeconds(4);
long start = System.nanoTime();
Object r = runInSandboxWithTimeout(script, input, budget); // your harness
long elapsed = (System.nanoTime() - start) / 1_000_000L;
if (elapsed >= budget.toMillis() * 0.8) {
    LOGGER.warn("Script near timeout budget ({}ms / {}ms); consider refactoring", elapsed, budget.toMillis());
}

Try / catch

// NonTransientException is not retriable; fail the task cleanly.
try {
    Object result = ScriptEvaluator.eval(script, input);
} catch (NonTransientException e) {
    // record reason, mark task FAILED, do NOT retry
    task.setReasonForIncompletion(e.getMessage());
    task.setStatus(TaskModel.Status.FAILED);
}

Prevention

When it happens

Trigger: Calling ScriptEvaluator.eval(script, input) (directly or via an inline JavascriptTask / expression evaluator) with a script containing an infinite loop, a very heavy computation, or a blocking call that exceeds the configured maxExecutionTimeSeconds. Only fires when the context pool is enabled.

Common situations: A workflow uses a JavaScript expression task with `while(true){}` or unbounded recursion; an input-driven script whose size grew past the 4s budget under load; maxExecutionTimeSeconds left at the 4s default while scripts legitimately need longer; context pool enabled to reuse contexts but a script regresses on latency.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/7fab2369915f26f1. Report an issue: GitHub.