denoland/deno · error
Inspector deregister handler already exists and is alive.
Error message
Inspector deregister handler already exists and is alive.
What it means
deno_core's inspector supports exactly one deregister handler: add_deregister_handler() hands out a oneshot Receiver that fires when the inspector is dropped, and the slot holds a single sender. Calling add_deregister_handler() again while the previous sender is still present and not canceled panics — the API is designed for one owner of that notification.
Source
Thrown at libs/core/inspector.rs:1237
let _ = self.state.poll_sessions(None).unwrap();
std::thread::sleep(std::time::Duration::from_millis(1));
}
}
/// Obtain a sender for proxy channels.
pub fn get_session_sender(&self) -> UnboundedSender<InspectorSessionProxy> {
self.new_session_tx.clone()
}
/// Create a channel that notifies the frontend when inspector is dropped.
///
/// NOTE: Only a single handler is currently available.
pub fn add_deregister_handler(&self) -> oneshot::Receiver<()> {
let maybe_deregister_tx = self.deregister_tx.borrow_mut().take();
if let Some(deregister_tx) = maybe_deregister_tx
&& !deregister_tx.is_canceled()
{
panic!("Inspector deregister handler already exists and is alive.");
}
let (tx, rx) = oneshot::channel::<()>();
self.deregister_tx.borrow_mut().replace(tx);
rx
}
/// Capture an incoming `Network.*` event payload into the shared body buffer
/// before it is broadcast to sessions. Called from
/// `op_inspector_emit_protocol_event` so subsequent
/// `Network.getResponseBody`/`streamResourceContent`/`getRequestPostData`
/// CDP commands have something to return.
///
/// Returns `true` if the event should still be broadcast to sessions, or
/// `false` if the event was fully consumed by the buffer. Matches Node's
/// `NetworkAgent`: `dataSent` is purely a capture event, and `dataReceived`
/// is only forwarded once `streamResourceContent` has flipped the entry
/// into streaming mode.
pub fn capture_network_event(View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Drop (or let fall out of scope) the previous Receiver before requesting another handler
- Restructure to register the deregister handler once per inspector and share the receiver
- When upgrading deno_core, check the changelog — the lifecycle API may have changed shape
- Reproduce in a minimal embedder and report to denoland/deno_core if the constraint seems wrong
Example fix
// before — second live handler panics let rx1 = inspector.add_deregister_handler(); let rx2 = inspector.add_deregister_handler(); // panic // after — one handler at a time let rx1 = inspector.add_deregister_handler(); drop(rx1); // cancel the previous handler first let rx2 = inspector.add_deregister_handler();
Defensive patterns
Strategy: validation
Validate before calling
// embedder: one live deregister handler at a time
use std::sync::Mutex;
static DEREG_RX: Mutex<Option<oneshot::Receiver<()>>> = Mutex::new(None);
fn replace_deregister_handler(inspector: &Inspector) {
let mut slot = DEREG_RX.lock().unwrap();
slot.take(); // drop + cancel the previous handler first
*slot = Some(inspector.add_deregister_handler());
} Prevention
- Register the deregister handler once per inspector and share the receiver
- Drop the old Receiver before requesting a new one
- Re-check embedder lifecycle code when upgrading deno_core — the single-handler rule is enforced with a panic
When it happens
Trigger: Embedder or runtime glue built on deno_core calls add_deregister_handler() a second time without the first Receiver having been dropped or its sender canceled — e.g. re-creating an inspector client on the same inspector after a session ends.
Common situations: Custom embedders wiring inspector lifecycle events; internal CLI flows around --inspect; deno_core upgrades tightening the single-handler rule so previously-tolerated patterns now panic.
Related errors
- op {} was not marked as #[op2(reentrant)], but re-entrantly
- wasm streaming callback invoked before the JS handler was se
- Expected data to be a string, Buffer, Uint8Array, or ArrayBu
- ERR_INSPECTOR_ALREADY_CONNECTED
- ERR_INSPECTOR_NOT_WORKER
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/c6ed3f497aeb89d6.
Report an issue: GitHub.