Open-Source Wikis

/

Deno

/

How to contribute

/

Debugging

denoland/deno

Debugging

How to track down what Deno is doing — both in Rust and in the JS layer that ships inside the runtime.

Logging

Deno uses a per-module logger driven by the DENO_LOG environment variable:

# All modules at debug level
DENO_LOG=debug ./target/debug/deno run script.ts

# Specific modules
DENO_LOG=deno_core=debug,deno_runtime=trace ./target/debug/deno run script.ts

# Trace level for a specific area
DENO_LOG=deno_npm=trace,deno_resolver=trace ./target/debug/deno run script.ts

Levels: error, warn, info, debug, trace. Many subsystems gate their detailed logging behind trace.

Backtraces

RUST_BACKTRACE=1 ./target/debug/deno run script.ts
RUST_BACKTRACE=full ./target/debug/deno run script.ts   # include all frames

For panics during build use the same env var with cargo.

println / dbg!

In the Rust layer:

eprintln!("Debug: {value:?}");
dbg!(some_value);

In the JS layer (ext/*/*.js, runtime/js/*.js, cli/js/*.js):

console.log('debug:', value);
console.error('debug:', value);

JS console.log from inside the runtime layer goes to stderr by default (the console extension is in ext/console).

lldb / rust-gdb

Both work. With lldb:

lldb ./target/debug/deno
(lldb) run eval 'console.log("test")'
(lldb) breakpoint set -n main

For breakpoints in async code, the function name is mangled — use breakpoint set -r <regex> or set on file:line. Symbol resolution is much better in debug builds (cargo build --bin deno).

Inspecting V8 internals

deno_core exposes V8 inspector hooks for the Chrome devtools protocol. Run:

./target/debug/deno run --inspect-brk script.ts

Then connect Chrome devtools to the printed URL. The inspector server lives in libs/inspector_server.

For lower-level V8 flags pass them via DENO_V8_FLAGS:

DENO_V8_FLAGS=--print-bytecode ./target/debug/deno run script.ts

Permission denials

When something fails with a permission error, the message indicates the category and resource. Re-run with -A (allow-all) to confirm it's just permissions, then narrow:

./target/debug/deno run -A script.ts
./target/debug/deno run --allow-read=./data --allow-net=api.example.com script.ts

To trace exactly which permission check fired, set DENO_LOG=deno_permissions=trace.

Module resolution issues

When import fails or resolves to the wrong file:

  1. Run deno info <specifier> — this prints the resolved module graph including npm/jsr resolutions.
  2. DENO_LOG=deno_resolver=trace,deno_npm=trace,deno_graph=trace
  3. Inspect the lockfile (deno.lock) — libs/lockfile controls what gets pinned. Stale lockfile entries are a common source of "wrong version resolved" bugs.
  4. For npm, deno install and node_modules/ (if BYONM is on) interact. Toggle "nodeModulesDir": "auto" vs "manual" in deno.json to confirm.

Type checker issues

Deno can use either the bundled JS-based tsc (cli/tsc/) or tsgo (libs/typescript_go_client). To see what's happening:

DENO_LOG=deno=debug ./target/debug/deno check script.ts

For tsc-specific issues, the snapshot lives in cli/tsc/00_typescript.js. Updating it requires the steps in tools/update_typescript.md.

LSP debugging

The LSP runs on stdio when launched via deno lsp. Editor logs are usually the easiest entry point:

  • VS Code: "Deno: Show Output" (Output panel → Deno Language Server)
  • Add "deno.internalDebug": true to settings for verbose LSP traces.
  • Server-side, set DENO_LOG=deno_lsp=trace.

For repro of an LSP bug, integration tests at tests/integration/lsp_tests.rs are the right home.

Snapshot mismatches

If you change extension JS and see "snapshot is stale" or runtime JS that doesn't match your edits, you're hitting a stale snapshot:

  • Confirm by building with --features hmr — if it works there, the snapshot is the issue.
  • cargo clean -p deno && cargo build --bin deno rebuilds the snapshot.
  • runtime/snapshot.rs and cli/snapshot/ are the relevant files.

Hangs and event loop issues

If deno run never exits, suspect either an open resource (timer, listener, request) or a stuck Tokio task:

  • Deno.unrefTimer(...) / unref'ed listeners can keep the loop alive.
  • Add console.log around suspect async paths — output ordering tells you where it hangs.
  • For Rust-side hangs, attach lldb and bt all to dump every thread.

Test-only debugging

For spec test failures:

  1. cargo test specs::<area>::<test_name> -- --nocapture to see stdout.
  2. The test runner respects DENO_LOG, so DENO_LOG=debug cargo test specs::<test> traces through.
  3. Check the .out for [WILDCARD] placeholders that might be over- or under-greedy.

Troubleshooting checklist

Symptom First thing to try
Build fails on first run Install cmake, protobuf, C/C++ toolchain; clone with --recurse-submodules
Test fails after pulling cargo clean -p deno && cargo build --bin deno to refresh snapshots
unwrap() panic in production binary RUST_BACKTRACE=full + check the file:line, replace with proper error
npm: import resolves wrong version Check deno.lock, run deno install, try toggling nodeModulesDir
LSP misbehaves Restart editor; check Deno output channel; reproduce with cargo test --test integration_tests lsp::...
Spec test passes locally, fails in CI OS-specific path separator? Use [WILDCARD] for paths. Order-dependent? Use [UNORDERED_*].

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Debugging – Deno wiki | Factory