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

  1. Confirm the browser/CDP session is alive (retry navigation or reconnect) before re-running the script.
  2. Check the embedded error {e} — 'SyntaxError' means fix the expression; 'Execution context was destroyed' means wait for navigation to settle first.
  3. Run document.readyState polling (wait_for_load equivalent) or a small no-op JS after navigation before evaluating real code.
  4. Wrap the logic in try/catch inside the JS itself so page exceptions surface as return values, not evaluation errors.
  5. 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

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


AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02). Data as JSON: /api/errors/1b4a08e132a71895. Report an issue: GitHub.