RightNow-AI/openfang · error · BrowserResponse
Scroll failed: {e}
Error message
Scroll failed: {e} What it means
cmd_scroll translates a direction/amount into dx/dy and evaluates scroll JS over CDP. When the CDP call returns Err, this message wraps the transport error — the scroll command never executed, so the viewport position is unchanged.
Source
Thrown at crates/openfang-runtime/src/browser.rs:572
async fn cmd_scroll(&self, direction: &str, amount: i32) -> BrowserResponse {
let (dx, dy) = match direction {
"up" => (0, -amount),
"down" => (0, amount),
"left" => (-amount, 0),
"right" => (amount, 0),
_ => (0, amount),
};
let js = format!("window.scrollBy({dx}, {dy}); JSON.stringify({{scrollX: window.scrollX, scrollY: window.scrollY}})");
match self.cdp.run_js(&js).await {
Ok(val) => {
let parsed: serde_json::Value = val
.as_str()
.and_then(|s| serde_json::from_str(s).ok())
.unwrap_or(val);
BrowserResponse::ok(parsed)
}
Err(e) => BrowserResponse::err(format!("Scroll failed: {e}")),
}
}
async fn cmd_wait(&self, selector: &str, timeout_ms: u64) -> BrowserResponse {
let sel_json = serde_json::to_string(selector).unwrap_or_default();
let max_ms = timeout_ms.min(30_000);
let polls = (max_ms / PAGE_LOAD_POLL_INTERVAL_MS).max(1);
for _ in 0..polls {
let js = format!("document.querySelector({sel_json}) ? 'found' : null");
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;View on GitHub (pinned to acf2587e46)
Solutions
- Read the interpolated {e} for the root CDP cause.
- Reconnect or restart the browser session and retry the scroll.
- Avoid interleaving scroll with navigation; wait_for_load before scrolling.
- Add retry-with-backoff for transient CDP transport errors.
Example fix
// before
let resp = browser.execute("scroll", &format!("{direction}|{amount}")).await?;
// after
browser.wait_for_load().await?;
let resp = match browser.execute("scroll", &format!("{direction}|{amount}")).await {
Ok(r) => r,
Err(_) => {
browser.reconnect().await?;
browser.execute("scroll", &format!("{direction}|{amount}")).await?
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Validate direction and settle the page before scrolling:
const DIRS: [&str; 4] = ["up", "down", "left", "right"];
if !DIRS.contains(&direction) { return Err(anyhow!("bad direction: {direction}")); }
browser.wait_for_load().await?; Type guard
fn is_cdp_transport_err(e: &anyhow::Error) -> bool {
let s = e.to_string();
s.contains("connection") || s.contains("closed") || s.contains("context")
} Try / catch
// Rust
match browser.execute("scroll", &format!("{direction}|{amount}")).await {
Ok(r) if r.success => Ok(r),
Ok(r) => Err(anyhow!(r.error)),
Err(e) if is_cdp_transport_err(&e) => {
browser.reconnect().await?;
browser.execute("scroll", &format!("{direction}|{amount}")).await.map_err(Into::into)
}
Err(e) => Err(e.into()),
} Prevention
- Restrict direction to up/down/left/right and clamp amount.
- Wait for load before scrolling to avoid context destruction.
- Reconnect the session on transport errors and retry once.
- Sequence scroll commands; avoid concurrent navigation.
When it happens
Trigger: The scroll JS sent via self.cdp.run_js resolves to Err: browser disconnected, execution context destroyed, or CDP evaluation failed/timed out.
Common situations: Scrolling during an in-flight navigation; headless browser crashed; CDP session dropped between commands; invalid direction/amount causing downstream JS issues in modified setups.
Related errors
- Navigate failed: {e}
- Screenshot failed: {e}
- ReadPage failed: {e}
- Navigate succeeded but page info failed: {e}
- Click failed
AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02).
Data as JSON: /api/errors/163b7ee63e8c25ff.
Report an issue: GitHub.