denoland/deno · error · Error

Deno.jupyter is only available in `deno jupyter` subcommand

Error message

Deno.jupyter is only available in `deno jupyter` subcommand

What it means

Deno.jupyter is published on the final Deno namespace in runtime/js/99_main.js as a lazy accessor: it caches the namespace once the `deno jupyter` bootstrap sets it, but until then the getter throws Error('Deno.jupyter is only available in `deno jupyter` subcommand'). Accessing the property under any other subcommand (deno run, test, repl) throws. Note the accessor property always exists, so presence checks like `'jupyter' in Deno` cannot detect availability — only an actual access inside try/catch can.

Source

Thrown at runtime/js/99_main.js:1131

    runtimeStart(
      denoVersion,
      v8Version,
      tsVersion,
      target,
    );

    // TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign`
    // above any properties that are defined elsewhere using `Object.defineProperty`
    // are lost.
    let jupyterNs = undefined;
    ObjectDefineProperty(finalDenoNs, "jupyter", {
      __proto__: null,
      get() {
        if (jupyterNs) {
          return jupyterNs;
        }
        throw new Error(
          "Deno.jupyter is only available in `deno jupyter` subcommand",
        );
      },
      set(val) {
        jupyterNs = val;
      },
    });

    for (let i = 0; i <= unstableFeatures.length; i++) {
      const id = unstableFeatures[i];
      const unstable = denoNsUnstableById[id];
      if (unstable) {
        ObjectDefineProperties(
          finalDenoNs,
          getSafeOwnPropertyDescriptors(unstable),
        );
      }
    }

View on GitHub (pinned to a961cdec3b)

Solutions

  1. Access Deno.jupyter only behind a try/catch probe (see defense) or inside code known to run under `deno jupyter`
  2. Route display output through console.log generally, and use Deno.jupyter only when the probe succeeds
  3. Upgrade Deno if you need Deno.jupyter unconditionally — newer versions expose it in every subcommand

Example fix

// before
Deno.jupyter.broadcast('display_data', { data: { 'text/html': html } });

// after
function getJupyter() {
  try {
    return Deno.jupyter;
  } catch {
    return undefined;
  }
}
const jupyter = getJupyter();
if (jupyter) jupyter.broadcast('display_data', { data: { 'text/html': html } });
Defensive patterns

Strategy: try-catch

Validate before calling

function getJupyter() {
  try {
    return Deno.jupyter; // touching the property throws outside deno jupyter
  } catch {
    return undefined;
  }
}
const jupyter = getJupyter();
if (jupyter) {
  jupyter.broadcast('display_data', payload);
}

Try / catch

// wrap every access — even detection — because the getter throws
try {
  const { markdown } = Deno.jupyter;
  await markdown(md);
} catch {
  console.log(md); // plain fallback outside notebooks
}

Prevention

When it happens

Trigger: `Deno.jupyter.broadcast('display_data', ...)` in a script run with `deno run`; notebook helper modules reused in plain scripts; probing capabilities by touching Deno.jupyter at import time.

Common situations: Sharing rich-output helpers between notebooks and CLI tools; libraries that enhance output when a kernel is present; version drift, since newer Deno releases expose the jupyter namespace in all subcommands.

Related errors


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