{"record":{"id":"305894698e28fbe3","repo":"windmill-labs/windmill","slug":"the-expression-evaluation-took-too-long-to-execute","errorCode":null,"errorMessage":"The expression evaluation took too long to execute (>{EVAL_TIMEOUT_MS}ms)","messagePattern":"The expression evaluation took too long to execute \\(>(.+?)ms\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-jseval/src/lib.rs","lineNumber":962,"sourceCode":"// ── eval_simple_js for windmill-api batch rerun ──────────────────────\n\n#[cfg(feature = \"quickjs\")]\npub async fn eval_simple_js(\n    expr: String,\n    globals: HashMap<String, serde_json::Value>,\n) -> anyhow::Result<Box<RawValue>> {\n    let memory_limit = EVAL_SIMPLE_JS_MEMORY_LIMIT_BYTES;\n    let handle = tokio::runtime::Handle::current();\n    tokio::time::timeout(\n        std::time::Duration::from_millis(EVAL_TIMEOUT_MS),\n        tokio::task::spawn_blocking(move || {\n            handle\n                .block_on(async move { eval_simple_js_inner(&expr, &globals, memory_limit).await })\n        }),\n    )\n    .await\n    .map_err(|_| {\n        anyhow::anyhow!(\"The expression evaluation took too long to execute (>{EVAL_TIMEOUT_MS}ms)\")\n    })??\n}\n\n#[cfg(feature = \"quickjs\")]\nasync fn eval_simple_js_inner(\n    expr: &str,\n    globals: &HashMap<String, serde_json::Value>,\n    memory_limit: usize,\n) -> anyhow::Result<Box<RawValue>> {\n    let runtime = AsyncRuntime::new()?;\n    runtime.set_memory_limit(memory_limit).await;\n    let context = AsyncContext::full(&runtime).await?;\n\n    async_with!(context => |ctx| {\n        let js_globals = ctx.globals();\n\n        // Set up each named global\n        for (name, value) in globals {","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-jseval/src/lib.rs#L944-L980","documentation":"The eval_simple_js path (used by windmill-api for batch rerun) enforces the same EVAL_TIMEOUT_MS wall-clock limit as transform evals. When the spawned evaluation does not finish in time, the timed join returns this error and the underlying task is dropped.","triggerScenarios":"A simple JS expression in a batch rerun containing a long/infinite loop or operating on data large enough that evaluation exceeds the timeout window.","commonSituations":"Re-running a historical run whose expression now processes bigger data; an expression edited to include an accidental while(true); very slow string processing on large payloads.","solutions":["Simplify or bound the expression (remove unbounded loops, shrink data)","Move heavy work out of the expression into a script step","Raise EVAL_TIMEOUT_MS if the evaluation is legitimately long but terminates"],"exampleFix":"// before\nlet s = ''; for (let i = 0; i < 1e9; i++) s += i;\n// after\nitems.reduce((acc, x) => acc + x.value, 0)","handlingStrategy":"try-catch","validationCode":"// keep expressions bounded; reject obviously heavy code before eval\nif (/while\\s*\\(\\s*true/.test(expr)) throw new Error('unbounded loop in expression');","typeGuard":null,"tryCatchPattern":"try {\n  const result = await evalSimpleJs(expr, globals);\n} catch (e) {\n  if (String(e).includes('took too long to execute')) {\n    // rewrite expression or move work to a script step\n  }\n  throw e;\n}","preventionTips":["Never put while(true)/heavy loops in simple expressions","Bound input sizes before evaluation","Raise EVAL_TIMEOUT_MS only with justification"],"tags":["javascript","timeout","batch-rerun"],"backgroundTag":"expression-evaluation-timeout","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}