RightNow-AI/openfang · error · BrowserResponse
Click failed
Error message
Click failed
What it means
cmd_click evaluates a JS snippet via CDP that clicks the element matching a selector and returns {success, error} JSON. When the script reports success=false, this fallback message 'Click failed' is used if the script did not include an 'error' string — i.e. the click script itself determined the click could not be performed (element not found, not clickable).
Source
Thrown at crates/openfang-runtime/src/browser.rs:464
for (const e of all) {{
if (e.textContent.trim().toLowerCase().includes(lower)) {{ el = e; break; }}
}}
}}
if (!el) return JSON.stringify({{success: false, error: 'Element not found: ' + sel}});
el.scrollIntoView({{block: 'center'}});
el.click();
return JSON.stringify({{success: true, tag: el.tagName, text: el.textContent.substring(0, 100).trim()}});
}})()"#
);
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);
if parsed["success"].as_bool() == Some(false) {
return BrowserResponse::err(
parsed["error"]
.as_str()
.unwrap_or("Click failed")
.to_string(),
);
}
// Wait briefly for any navigation triggered by click
tokio::time::sleep(Duration::from_millis(500)).await;
self.wait_for_load().await;
match self.page_info().await {
Ok(info) => BrowserResponse::ok(info),
Err(_) => BrowserResponse::ok(parsed),
}
}
Err(e) => BrowserResponse::err(format!("Click failed: {e}")),
}
}
View on GitHub (pinned to acf2587e46)
Solutions
- Verify the selector matches exactly one visible element (test it in the browser console with document.querySelector).
- Use cmd_wait on the selector before clicking to ensure it exists in the DOM.
- Inspect the parsed error payload — the script usually returns a more specific 'error' field than this fallback.
- For shadow DOM or iframes, use a selector strategy that penetrates them or switch frames first.
Example fix
// before
let _ = browser.execute("click", selector).await?;
// after
browser.execute("wait", &format!("{selector}|5000")).await?;
let resp = browser.execute("click", selector).await?;
if !resp.success { return Err(anyhow!(resp.error)); } Defensive patterns
Strategy: validation
Validate before calling
// Ensure the element exists before clicking:
let wait = browser.execute("wait", &format!("{selector}|5000")).await?;
if !wait.success { return Err(anyhow!("element not present: {selector}")); } Type guard
fn click_failed_no_reason(resp: &BrowserResponse) -> bool {
!resp.success && resp.error == "Click failed"
} Try / catch
// Rust
let resp = browser.execute("click", selector).await?;
if !resp.success {
if resp.error == "Click failed" {
// no script-side reason — most likely selector miss; wait and retry once
browser.execute("wait", &format!("{selector}|3000")).await?;
return browser.execute("click", selector).await.map_err(Into::into);
}
return Err(anyhow!(resp.error));
}
Ok(resp) Prevention
- Always wait for the selector before clicking.
- Validate selectors in devtools/console first.
- Prefer stable data-* attributes over generated class names.
- Handle iframes/shadow DOM explicitly before clicking inside them.
When it happens
Trigger: Running the click JS over CDP returns a value whose parsed["success"] is false and parsed["error"] is missing or not a string — e.g. the injected script failed to find the selector and returned success:false without a message.
Common situations: Selector typo or element rendered client-side after the click attempt; element inside an iframe the script doesn't reach; stale selector after a re-render.
Related errors
AI-assisted analysis of RightNow-AI/openfang@acf2587e46 (2026-09-02).
Data as JSON: /api/errors/1f9e10c86e5beaa9.
Report an issue: GitHub.