denoland/deno · critical

JS PANIC: {}

Error message

JS PANIC: {}

What it means

op_panic is deno_core's escape hatch for JS runtime internals: when internal bootstrap/extension JS reaches an impossible state, it calls this op, which prints `JS PANIC: <message>` to stderr and panics the runtime, taking down the process. The message names the internal invariant that failed. It is unrelated to user exceptions — uncaught user errors go through the normal error path.

Source

Thrown at libs/core/ops_builtin.rs:155

  ops_builtin_v8::op_op_names,
  ops_builtin_v8::op_current_user_call_site,
  ops_builtin_v8::op_set_format_exception_callback,
  ops_builtin_v8::op_event_loop_has_more_work,
  ops_builtin_v8::op_immediate_check,
  ops_builtin_v8::op_leak_tracing_enable,
  ops_builtin_v8::op_leak_tracing_submit,
  ops_builtin_v8::op_leak_tracing_get_all,
  ops_builtin_v8::op_leak_tracing_get,
  ops_builtin_v8::op_get_ext_import_meta_proto
}

#[op2(fast)]
pub fn op_panic(#[string] message: String) {
  #[allow(clippy::print_stderr, reason = "intentional panic output")]
  {
    eprintln!("JS PANIC: {}", message);
  }
  panic!("JS PANIC: {}", message);
}

/// Return map of resources with id as key
/// and string representation as value.
#[op2]
pub fn op_resources(state: &mut OpState) -> Vec<(ResourceId, String)> {
  state
    .resource_table
    .names()
    .map(|(rid, name)| (rid, name.to_string()))
    .collect()
}

#[op2(fast)]
fn op_add(a: i32, b: i32) -> i32 {
  a + b
}

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Reinstall/update Deno so the binary, snapshot, and JS runtime all come from the same version
  2. Read the message — it names the failing invariant, which maps to a specific runtime subsystem
  3. If your own code reaches for core.ops.op_panic, throw a normal Error instead
  4. Report with the exact JS PANIC message and a reproducer when it comes from Deno internals

Example fix

// before — extension code invokes the internal panic op
Deno.core.ops.op_panic("unreachable branch");

// after — throw a catchable JS error
throw new Error("unreachable branch");
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: Internal Deno JS code (runtime bootstrap, core extensions) signaling an unreachable state, or embedder/extension code deliberately calling Deno.core.ops.op_panic. The panic is process-fatal and cannot be caught from JS.

Common situations: Mismatched runtime pieces after a partial Deno upgrade or corrupted install (binary vs snapshot vs JS); snapshots built from a different deno_core version; genuine bugs in Deno internals on unusual code paths.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e424ac2863b7974a. Report an issue: GitHub.