denoland/deno · critical
web workers are not supported
Error message
web workers are not supported
What it means
runtime/worker.rs:322 is the default create_web_worker_cb inside WorkerOptions::default(); it is an unimplemented!() panic that fires only if a runtime embedder never supplied a real web-worker factory. The Deno CLI always overrides this callback, so end users should never see it — seeing it means a custom deno_runtime/deno_core integration started a JS Worker (new Worker(...)) without wiring nested-worker creation.
Source
Thrown at runtime/worker.rs:322
// user code.
pub should_wait_for_inspector_session: bool,
/// If Some, print a low-level trace output for ops matching the given patterns.
pub trace_ops: Option<Vec<String>>,
pub cache_storage_dir: Option<std::path::PathBuf>,
pub origin_storage_dir: Option<std::path::PathBuf>,
pub stdio: Stdio,
pub enable_raw_imports: bool,
pub enable_stack_trace_arg_in_ops: bool,
pub unconfigured_runtime: Option<UnconfiguredRuntime>,
}
impl Default for WorkerOptions {
fn default() -> Self {
Self {
create_web_worker_cb: Arc::new(|_| {
unimplemented!("web workers are not supported")
}),
skip_op_registration: false,
seed: None,
unsafely_ignore_certificate_errors: Default::default(),
should_break_on_first_statement: Default::default(),
should_wait_for_inspector_session: Default::default(),
trace_ops: Default::default(),
format_js_error_fn: Default::default(),
origin_storage_dir: Default::default(),
cache_storage_dir: Default::default(),
extensions: Default::default(),
startup_snapshot: Default::default(),
residual_lazy_js_sources: &[],
residual_lazy_esm_sources: &[],
create_params: Default::default(),
bootstrap: Default::default(),
stdio: Default::default(),
enable_raw_imports: false,View on GitHub (pinned to 89f33cbef2)
Solutions
- Provide a real create_web_worker_cb when constructing WorkerOptions (Arc<dyn Fn(WebWorkerOptions) -> Result<WebWorker>>), typically reusing deno_runtime::worker::create_web_worker_init_cb and re-registering your extensions
- Decide the embedding policy: disable worker creation entirely by erroring deliberately in the callback instead of leaving the unimplemented!() default
- If you intended the Deno CLI behavior, run scripts through the deno binary rather than a hand-rolled runtime bootstrap
Example fix
// before (Rust embedder)
let options = WorkerOptions::default(); // create_web_worker_cb = unimplemented!
// after
let options = WorkerOptions {
create_web_worker_cb: Arc::new(|init| {
Ok(deno_runtime::worker::WebWorker::bootstrap_from_options(
init.main_module,
deno_runtime::worker::WebWorkerOptions { /* extensions, perms, ... */ ..init },
))
}),
..Default::default()
}; Defensive patterns
Strategy: validation
Validate before calling
// Rust, before creating the runtime
fn assert_workers_supported(options: &WorkerOptions) -> Result<(), String> {
let ok = matches!(
std::thread::catch_unwind(std::panic::AssertUnwindSafe(|| {
// probing is unsafe; instead track whether the cb was set by construction
false
})),
_ => false
);
let _ = ok;
// Practical check: gate on your own builder flag
if !options.extensions.is_empty() /* proxy for custom bootstrap */ {
Ok(())
} else {
Err("create_web_worker_cb not supplied".into())
}
} Try / catch
// JS side: you cannot catch a Rust unimplemented!() panic — prevent it in the embedder instead.
// Rust embedder: wrap runtime execution in catch_unwind to log which feature requested a Worker.
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
rt.block_on(main_js_future)
}));
if result.is_err() { /* log 'web workers requested but unsupported' */ } Prevention
- Never ship WorkerOptions::default() to production; always set create_web_worker_cb explicitly
- Make worker support a documented capability flag of your embedding and test new Worker(...) in your test suite
- Alternatively deliberately return an error from the callback so JS gets a catchable failure instead of a panic
When it happens
Trigger: Embedding deno_runtime with WorkerOptions::default() (or any Options struct where create_web_worker_cb was never set) and then executing JavaScript that calls new Worker(new URL("./w.js", import.meta.url), { type: "module" }) or new SharedWorker.
Common situations: Building custom runtimes/sandboxes on deno_core+deno_runtime (server-side scripting hosts, plugin systems, edge platforms); copying a minimal deno_runtime example that predates the callback being required; upgrading deno_runtime versions where defaults became stricter about nested workers.
Related errors
- REPL thread failed to start
- failed to evaluate expression
- Deno.bundle() is not available in compiled binaries (`deno c
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/8898e4c02193c73c.
Report an issue: GitHub.