Mintplex-Labs/anything-llm · error
No webSocketDebuggerUrl — is Chromium running?
Error message
No webSocketDebuggerUrl — is Chromium running?
What it means
Identical guard to cdp-eval's, in the cdp-input helper (click/type/key injection): GET http://127.0.0.1:9222/json/version succeeded but the parsed JSON has no webSocketDebuggerUrl, so there is no browser-level WS endpoint to attach Input.* domains to. Something is serving /json/version on 9222, but it is not a fully remote-debuggable Chromium.
Solutions
- Restart Chromium with --remote-debugging-port=9222 and a dedicated --user-data-dir so the browser WS endpoint is exposed
- curl http://127.0.0.1:9222/json/version and confirm webSocketDebuggerUrl is non-empty before invoking click/type/key
- Find and stop the squatter on 9222 or move your debug port and update the helper's URL
- If a puppeteer/playwright session owns the browser, drive input through that session instead of this helper
Example fix
# before chromium & # no debugging endpoint -> error # after chromium --remote-debugging-port=9222 --user-data-dir=/tmp/oc-chrome https://example.com & node cdp-input.js click 100 200
Defensive patterns
Strategy: validation
Validate before calling
async function cdpInputReady() {
const v = await (await fetch('http://127.0.0.1:9222/json/version')).json();
return Boolean(v.webSocketDebuggerUrl);
}
if (!(await cdpInputReady())) throw new Error('relaunch Chromium: --remote-debugging-port=9222 --user-data-dir=/tmp/oc-chrome'); Type guard
function hasDebuggerUrl(v: unknown): v is { webSocketDebuggerUrl: string } {
return typeof (v as any)?.webSocketDebuggerUrl === 'string' && (v as any).webSocketDebuggerUrl.length > 0;
} Try / catch
try { await sendInput('click', x, y); } catch (e) { if (/No webSocketDebuggerUrl/.test(e.message)) { await relaunchChromiumWithDebugPort(); await sendInput('click', x, y); } else throw e; } Prevention
- Never drive input against the user's daily browser — keep the debug Chromium instance dedicated to the agent
- Check /json/version for webSocketDebuggerUrl before every input batch; input has no retry otherwise
- Use one shared readiness check for both cdp-eval and cdp-input since they fail identically
When it happens
Trigger: Chromium running without --remote-debugging-port while another DevTools-protocol-speaking service owns 9222; headless shells or embedded Chromium builds whose /json/version omits the browser WS URL; managed/enterprise Chromium with the debug WS endpoint stripped.
Common situations: The desktop agent's Chromium got replaced by the user's normal browser session; a chromedriver or puppeteer-connected Chrome already bound to 9222 with a single-client WS URL; port 9222 forwarded to a container that only implements part of the DevTools HTTP API.
Related errors
- No browser pages open.
- No webSocketDebuggerUrl — is Chromium running?
- click requires coordinates
- key requires argument (e.g. Enter, Tab, Escape)
- No browser pages open.
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/3ed04a3474d686bb.
Report an issue: GitHub.
Appendix: source
Thrown at open-computer/services/interface-service/utils/cdp-input.js:77
ws.on("message", handler);
ws.send(JSON.stringify(msg));
});
}
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
// Randomized human-like delay between keystrokes
function keystrokeDelay() {
return 30 + Math.floor(Math.random() * 60);
}
async function main() {
const versionRaw = await httpGet("http://127.0.0.1:9222/json/version");
const version = JSON.parse(versionRaw);
const browserWsUrl = version.webSocketDebuggerUrl;
if (!browserWsUrl) throw new Error("No webSocketDebuggerUrl — is Chromium running?");
const ws = await new Promise((resolve, reject) => {
const socket = new WebSocket(browserWsUrl);
const t = setTimeout(() => reject(new Error("WS connect timeout")), 5000);
socket.on("open", () => { clearTimeout(t); resolve(socket); });
socket.on("error", (err) => { clearTimeout(t); reject(err); });
});
try {
// Find target page
const { targetInfos } = await cdpSend(ws, "Target.getTargets");
const pages = targetInfos.filter(
(t) => t.type === "page" && !t.url.startsWith("chrome://") && !t.url.startsWith("devtools://")
);
if (pages.length === 0) throw new Error("No browser pages open.");
// Determine target URL filter (always last arg if it doesn't look like a coordinate/text)
let targetUrl = "";View on GitHub (pinned to 3aec848f28)