{"record":{"id":"ccd028b545f5e816","repo":"denoland/deno","slug":"upstream-json-list-at-host-returned","errorCode":null,"errorMessage":"upstream /json/list at {host} returned {}","messagePattern":"upstream /json/list at (.+?) returned (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/tools/desktop_devtools.rs","lineNumber":722,"sourceCode":"  let stream = TcpStream::connect(host).await?;\n  let io = TokioIo::new(stream);\n  let (mut sender, conn) = hyper::client::conn::http1::handshake(io)\n    .await\n    .map_err(|e| anyhow!(\"http handshake to {host} failed: {e}\"))?;\n  tokio::spawn(async move {\n    if let Err(err) = conn.await {\n      log::trace!(\"[devtools-mux] upstream conn closed: {err:?}\");\n    }\n  });\n\n  let req = hyper::Request::builder()\n    .method(http::Method::GET)\n    .uri(\"/json/list\")\n    .header(http::header::HOST, host.to_string())\n    .body(Empty::<Bytes>::new())?;\n  let resp = sender.send_request(req).await?;\n  if !resp.status().is_success() {\n    bail!(\"upstream /json/list at {host} returned {}\", resp.status());\n  }\n  let body = resp.collect().await?.to_bytes();\n  let value: Value = serde_json::from_slice(&body)\n    .with_context(|| format!(\"upstream /json/list at {host} not JSON\"))?;\n\n  let ws_url = value\n    .as_array()\n    .and_then(|arr| {\n      arr.iter().find_map(|v| {\n        // Skip targets that are our own DevTools frontend window — when\n        // openDevtools() creates a CEF window pointed at inspector.html,\n        // CEF registers it as a debuggable target. Connecting to it\n        // instead of the real app window would show \"DevTools for\n        // DevTools\".\n        let url = v.get(\"url\").and_then(|u| u.as_str()).unwrap_or(\"\");\n        if url.contains(\"/devtools/\") || url.contains(\"devtools://\") {\n          return None;\n        }","sourceCodeStart":704,"sourceCodeEnd":740,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/tools/desktop_devtools.rs#L704-L740","documentation":"The desktop devtools multiplexer fetches `/json/list` over HTTP from the embedded browser's remote-debugging endpoint to discover the page target's webSocketDebuggerUrl, and bails on any non-success status. The upstream debug server either isn't serving yet, is on a different host/port than expected, or rejected the request.","triggerScenarios":"The mux connects before the CEF/browser debug endpoint is ready (startup race), the configured host/port doesn't match the actual remote-debugging address, another process occupies the port, or the browser process died between connection and the HTTP request. Any 4xx/5xx status lands here.","commonSituations":"Opening devtools immediately at app launch; a stale port left over from a previous crashed run; a second debuggable instance already holding the endpoint; proxies/firewalls interfering with localhost HTTP.","solutions":["Retry the devtools connection after the app window is fully up — the most common cause is a startup race.","Curl the endpoint yourself: `curl http://<host>:<port>/json/list` — if that fails, the address is wrong or the server isn't listening.","Kill stale instances of the app/browser holding the debugging port, then relaunch.","Verify the remote-debugging port configuration matches what the mux is given, and prefer 127.0.0.1."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"# Wait until the remote-debugging endpoint answers before opening devtools\nfor i in $(seq 1 20); do\n  curl -fsS \"http://127.0.0.1:${PORT}/json/list\" >/dev/null && break\n  sleep 0.5\ndone","typeGuard":null,"tryCatchPattern":"// Client-side pattern around the mux/devtools attach\nasync function attachWithRetry(url: string, attempts = 5): Promise<Response> {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      const r = await fetch(`${url}/json/list`);\n      if (r.ok) return r;\n    } catch { /* not ready */ }\n    await new Promise((r) => setTimeout(r, 500 * (i + 1)));\n  }\n  throw new Error(`devtools endpoint at ${url} not responding`);\n}","preventionTips":["Give the app a startup grace period before attaching devtools; the debug server races process init.","Prefer 127.0.0.1 and the exact configured port; avoid port guessing.","Ensure only one debuggable app instance runs — stale instances hold the endpoint."],"tags":["desktop","devtools","remote-debugging","network","cef"],"backgroundTag":"devtools-remote-debugging-unavailable","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T04:17:50.494Z"}