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
- Inspect the failing script for loops/recursion/blocking calls and bound it algorithmically.
- Raise the budget via `conductor.systemTaskEvalTimeoutSeconds` (or the ScriptEvaluator initializer maxSeconds arg) only if the script is genuinely O(n) over large input.
- Refactor the logic out of inline JS into a dedicated worker task for long-running computation.
- Keep the context pool disabled (the default) unless you fully control every script, since pooled contexts can change latency characteristics.
- 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
- Cap all loops in inline JS with an explicit iteration bound.
- Keep the default 4s budget unless scripts are proven to need more.
- Run new scripts in a local GraalJS harness with the same timeout before deploying.
- Avoid blocking/host calls — the engine disables load/print/console/host access by design.
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
- Script execution interrupted: %s
- Error evaluating the script `%s`
- Error evaluating the script `%s` at line %d
- Error evaluating the script %s
- %s
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/7fab2369915f26f1.
Report an issue: GitHub.