Debugging

Collect plain errors, logs, diagnostics, and interactive results

Start with a parseable uncaught-error format:

elide --error-format=plain run app.js

Plain errors go to stderr and include a short stack, leaving normal program output on stdout. Increase Elide’s own logging with --verbose or --debug, or set ELIDE_LOG=debug.

Viewing an uncaught program error in Elide

Attach a debugger

--debugger takes either a mode or a JDWP address, and the two pick different engines. A mode (cdp, dap, or the bare flag) debugs guest JavaScript, TypeScript and Python; an address (5005, host:5005) attaches Java’s JDWP agent to a JVM program or JVM tests. An address does nothing for guest code. elide run --debugger=5005 app.js runs the script undebugged and exits 0, so reach for a mode unless the thing you are debugging runs on the JVM.

Choose DAP for a compatible IDE or CDP for Chrome DevTools. Both bind to 127.0.0.1 by default; DAP uses port 4711 and CDP uses the shared development server on port 1337. Override either address component explicitly:

elide --debugger=dap --debugger-host=127.0.0.1 --debugger-port=5678 run app.js
elide run --debugger=cdp --debugger-host=127.0.0.1 --debugger-port=9230 app.js

The host accepts a hostname, IPv4 address, or IPv6 address (such as ::1); the port must be between 1024 and 65535, matching the GraalVM instruments’ supported range. These flags require an active --debugger; they do not enable debugging on their own. DAP waits for an attached client before executing guest code. For CDP, use the DevTools link printed by Elide; changing the CDP address also moves its shared MCP listener.

--debugger-host reaches the DAP listener directly. CDP’s inspector is loopback-only and takes its host from the shared development server instead, so on an elide test run — which starts no development server — a CDP host is not applied and the inspector stays on 127.0.0.1. Use --debugger=dap when the listener has to be reachable from outside the machine.

Debug a test run

A test run is where both engines can be in play at once, so a bare --debugger (or --debugger=auto, the same request spelled out) attaches to each: the guest engine takes CDP, and JVM tests get a JDWP agent on 127.0.0.1:5005, which suspends the forked launcher until a debugger attaches.

elide test --debugger
elide test --debugger=dap --debugger-port=5678
elide test --debugger sample.test.mts

Naming a mode selects the guest debugger alone, addressed by --debugger-host and --debugger-port — the host reaching DAP only, as above. A mode is not a JDWP address, so JVM tests keep running undebugged and Elide says which half of the run it attached to; use the bare flag to cover both.

Giving the flag an address rather than a mode moves the JDWP agent, and selects the JVM engine alone:

elide test --debugger=5005
elide test --debugger=0.0.0.0:5005
elide run --debugger=5005

A bare port leaves the agent on loopback, 127.0.0.1:5005 by default; the host:port form binds it elsewhere. JDWP has no authentication and an attached client controls the JVM, so widen it only on a network you trust — the 0.0.0.0 line above is that decision made deliberately.

The port has to be one the agent can bind, 1024 to 65535. Do not narrow such a run with a path: JUnit selects by class and package, never by file, so a path argument makes the JVM tests skip themselves and there is nothing left for the agent to attach to. Narrow by package name instead.

Because an address selects the JVM engine, it attaches nothing when a run has no JVM code in it: elide test --debugger=5005 in a project of *.test.ts files debugs nothing, and Elide says so rather than leaving an IDE waiting on a port that never opens. Guest tests want a mode.

Pass a path to narrow the run to the file you mean to step through. While a debugger is attached, guest files run one at a time whatever --concurrency asks for: the listener belongs to the engine rather than to one file’s context, so several at once would sit suspended behind a single debug session.

Debugger access can control the running program, the JDWP agent as much as the guest listeners. Keep the loopback default and use an SSH tunnel for remote access. Only bind to 0.0.0.0 or another externally reachable interface on a trusted, access-controlled network.

CDP is powered by GraalVM’s Chrome inspector; see its Chrome debugger docs for protocol-level detail.

Bound a reproduction

Use the global timeout for guest execution:

elide --timeout=30s run app.js

A timeout exits with code 124.

Inspect the runtime

elide info
elide agent diagnostics
elide agent diagnostics --json

Agent diagnostics report the version, platform, output mode, and resolved crash directory. If Elide wrote a crash report, attach it with the exact command and expected behavior when filing an issue.

Experiment interactively

Use elide repl to reduce a runtime problem to a small expression. See the REPL guide for language switching and history commands.

Record and profile execution

Use the Monitoring and Profiling guide to capture JFR recordings, inspect managed-heap dumps, attach with jcmd, and resolve JIT-compiled guest code in Linux perf.