denoland/deno · error
Inspector UUID already in map
Error message
Inspector UUID already in map
What it means
The inspector server keeps a HashMap<Uuid, InspectorInfo>; each inspector is created with Uuid::new_v4 (inspector_server.rs:516) and registered over a channel, and the server task panics if the uuid is already in the map. Because v4 UUIDs are random, a real hit almost always means duplicate registration rather than chance: the same InspectorInfo was sent twice, or a fork() duplicated process state so a child re-registers a colliding identity.
Source
Thrown at libs/dcore/src/inspector_server.rs:441
_ = server_handler => {},
}
}
async fn listen_for_new_inspectors(
mut register_inspector_rx: UnboundedReceiver<InspectorInfo>,
inspector_map: Rc<RefCell<HashMap<Uuid, InspectorInfo>>>,
) {
while let Some(info) = register_inspector_rx.next().await {
eprintln!(
"Debugger listening on {}",
info.get_websocket_debugger_url(&info.host.to_string())
);
eprintln!("Visit chrome://inspect to connect to the debugger.");
if info.wait_for_session {
eprintln!("Deno is waiting for debugger to connect.");
}
if inspector_map.borrow_mut().insert(info.uuid, info).is_some() {
panic!("Inspector UUID already in map");
}
}
}
/// The pump future takes care of forwarding messages between the websocket
/// and channels. It resolves when either side disconnects, ignoring any
/// errors.
///
/// The future proxies messages sent and received on a WebSocket
/// to a UnboundedSender/UnboundedReceiver pair. We need these "unbounded" channel ends to sidestep
/// Tokio's task budget, which causes issues when JsRuntimeInspector::poll_sessions()
/// needs to block the thread because JavaScript execution is paused.
///
/// This works because UnboundedSender/UnboundedReceiver are implemented in the
/// 'futures' crate, therefore they can't participate in Tokio's cooperative
/// task yielding.
async fn pump_websocket_messages(
mut websocket: WebSocket<TokioIo<hyper::upgrade::Upgraded>>,View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Create and register each inspector exactly once per process; construct a fresh InspectorInfo (new Uuid::new_v4) for every registration
- Call fork() before any inspector/server is created, never after
- Deduplicate registration logic so only one code path sends InspectorInfo to the server
- If supervising multiple runtimes, ensure each gets its own inspector session rather than sharing a handle
Example fix
// before: fork after the inspector exists; child re-registers same uuid
let server = InspectorServer::new(addr, "main")?; // inspector created
let pid = unsafe { libc::fork() }; // child later panics: 'Inspector UUID already in map'
// after: fork first, then create inspector/server per process
let pid = unsafe { libc::fork() };
let server = InspectorServer::new(addr, if pid == 0 { "child" } else { "main" })?; Defensive patterns
Strategy: validation
Validate before calling
// In embeddings: register each inspector exactly once, keyed by runtime id.
let registered: HashSet<Uuid> = HashSet::new();
assert!(registered.insert(info.uuid.clone()),
"inspector {uuid} already registered", uuid = info.uuid); Prevention
- Fork before creating inspectors/servers, never after
- Construct a fresh InspectorInfo (new random uuid) per registration; never clone and re-register
- Keep exactly one code path that sends InspectorInfo to the server channel
- Disable the inspector server in fork-heavy test harnesses unless each child creates its own
When it happens
Trigger: An embedding manually re-sending an InspectorInfo registration over the channel; fork()ing a process after an inspector was created so parent and child both register; a custom runtime harness that clones and re-registers inspector handles when spawning workers.
Common situations: Prefork servers or test harnesses that fork after enabling --inspect; embeddings that build their own InspectorInfo instead of letting each runtime construct a fresh one; duplicated initialization code paths in multi-worker setups.
Related errors
- ERR_INSPECTOR_ALREADY_ACTIVATED
- ERR_INSPECTOR_NOT_ACTIVE
- the argument '{previous}' cannot be used with '{name}'
- ERR_CHILD_PROCESS_IPC_REQUIRED
- Expected data to be a string, Buffer, Uint8Array, or ArrayBu
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/d08759bd7ead02a9.
Report an issue: GitHub.