RightNow-AI/openfang · error · BrowserResponse
JS execution failed: {e}
Error message
JS execution failed: {e} What it means
cmd_run_js forwards the expression to the CDP connection (self.cdp.run_js) and wraps any Err into this error string. The library throws it whenever Runtime.evaluate fails at the transport or protocol level — connection loss, evaluation exception returned as an error, or an invalid execution context — not when the JS merely returns an unexpected value (that path returns Ok).
Source
Thrown at crates/openfang-runtime/src/browser.rs:601
if let Ok(val) = self.cdp.run_js(&js).await {
if val.as_str() == Some("found") {
return BrowserResponse::ok(
serde_json::json!({"found": true, "selector": selector}),
);
}
}
tokio::time::sleep(Duration::from_millis(PAGE_LOAD_POLL_INTERVAL_MS)).await;
}
BrowserResponse::err(format!(
"Timed out waiting for selector: {selector} ({max_ms}ms)"
))
}
async fn cmd_run_js(&self, expression: &str) -> BrowserResponse {
match self.cdp.run_js(expression).await {
Ok(val) => BrowserResponse::ok(serde_json::json!({"result": val})),
Err(e) => BrowserResponse::err(format!("JS execution failed: {e}")),
}
}
async fn cmd_back(&self) -> BrowserResponse {
match self.cdp.run_js("history.back(); 'ok'").await {
Ok(_) => {
tokio::time::sleep(Duration::from_millis(500)).await;
self.wait_for_load().await;
match self.page_info().await {
Ok(info) => BrowserResponse::ok(info),
Err(e) => {
BrowserResponse::err(format!("Back succeeded but page info failed: {e}"))
}
}
}
Err(e) => BrowserResponse::err(format!("Back failed: {e}")),
}
}View on GitHub (pinned to acf2587e46)
Solutions
- Confirm the browser/CDP session is alive (retry navigation or reconnect) before re-running the script.
- Check the embedded error {e} — 'SyntaxError' means fix the expression; 'Execution context was destroyed' means wait for navigation to settle first.
- Run document.readyState polling (wait_for_load equivalent) or a small no-op JS after navigation before evaluating real code.
- Wrap the logic in try/catch inside the JS itself so page exceptions surface as return values, not evaluation errors.
- If the script depends on page state, guard with a feature check (typeof foo !== 'undefined').
Example fix
// before: evaluate immediately after navigation
browser.cmd_run_js("window.app.getState()");
// after: wait for context, then evaluate defensively
browser.wait_for_load().await;
browser.cmd_run_js("(typeof window.app !== 'undefined') ? JSON.stringify(window.app.getState()) : 'null'"); Defensive patterns
Strategy: try-catch
Validate before calling
let alive = browser.cmd_run_js("1+1");
if alive.is_err() { /* CDP session is dead — reconnect or relaunch before real work */ } Type guard
fn is_eval_error(resp: &BrowserResponse) -> bool {
resp.error.as_deref().map(|e| e.starts_with("JS execution failed")).unwrap_or(false)
}
fn is_context_destroyed(resp: &BrowserResponse) -> bool {
resp.error.as_deref().map(|e| e.contains("context was destroyed")).unwrap_or(false)
} Try / catch
match browser.cmd_run_js(expr) {
Ok(r) => r,
Err(e) if e.contains("context was destroyed") => { wait_for_load(); browser.cmd_run_js(expr) }
Err(e) if e.contains("SyntaxError") => return Err(format!("bad script: {e}")),
Err(e) => Err(e),
} Prevention
- Probe the session with a trivial expression before running important scripts.
- Wrap page logic in an in-JS try/catch and return errors as values instead of throwing.
- Never evaluate immediately after navigation — poll document.readyState first.
- Keep scripts as single expressions (Runtime.evaluate semantics); avoid bare multi-statement code.
- Reconnect CDP sessions proactively in long-running automation instead of assuming liveness.
When it happens
Trigger: Calling the run_js command when the CDP WebSocket to the browser is closed or dropped, the target execution context was destroyed (page navigated or crashed mid-call), the expression has a syntax error that Chrome rejects at evaluation, or the browser process died.
Common situations: Evaluating JS right after clicking a link that navigates (context destroyed); a headless Chrome crash under memory pressure; sending multi-statement scripts where only expressions are safe; the automation session outliving the browser (timeout on the underlying tab).
Related errors
- Timed out waiting for selector: {selector} ({max_ms}ms)
- Back succeeded but page info failed: {e}
- Back failed: {e}
- Navigate failed: {e}
- Navigate succeeded but page info failed: {e}
AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02).
Data as JSON: /api/errors/1b4a08e132a71895.
Report an issue: GitHub.