{"id":12680,"library":"wtfnode","title":"wtfnode - Node.js Exit Debugger","description":"wtfnode is a utility designed to help Node.js developers diagnose why their applications are not exiting gracefully. It provides enhanced and human-readable insights into active event loop handles, such as timers, sockets, and servers, which prevent a Node.js process from terminating. Leveraging Node's internal `process._getActiveHandles()`, wtfnode breaks down complex handle information into actionable details, including call site origins for listeners, making it easier to pinpoint the exact code keeping a program alive. The current stable version, 0.10.1, functions as a crucial diagnostic tool for stalled applications, differentiating itself from raw Node.js introspection by offering a higher-level, more interpretable view of the event loop. Its release cadence is driven by the community's need for robust debugging solutions for persistent processes.","status":"active","version":"0.10.1","language":"javascript","source_language":"en","source_url":"https://github.com/myndzi/wtfnode","tags":["javascript"],"install":[{"cmd":"npm install wtfnode","lang":"bash","label":"npm"},{"cmd":"yarn add wtfnode","lang":"bash","label":"yarn"},{"cmd":"pnpm add wtfnode","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Primarily designed for CommonJS; direct ESM import might not work as expected in older Node environments due to the package's age (v0.10.x). Use `require()` for consistency.","wrong":"import wtf from 'wtfnode';","symbol":"wtf","correct":"const wtf = require('wtfnode');"},{"note":"The `dump()` method is the primary API for printing open handles. It should be called on the imported `wtf` object.","wrong":"require('wtfnode').dump();","symbol":"dump","correct":"wtf.dump();"},{"note":"Options for `dump()` are passed as an object, not as direct arguments. `--fullstacks` is a command-line option, `fullstacks: true` is for the module API.","wrong":"wtf.dump(true);","symbol":"Options","correct":"wtf.dump({ fullstacks: true });"}],"quickstart":{"code":"const wtf = require('wtfnode');\n\nconsole.log('Starting wtfnode example. Press Ctrl+C to dump handles.');\n\n// Create an interval to keep the process alive\nconst intervalId = setInterval(() => {\n  console.log('Interval running...');\n}, 2000);\n\n// Create a server that will also keep the process alive\nconst http = require('http');\nconst server = http.createServer((req, res) => {\n  res.writeHead(200, { 'Content-Type': 'text/plain' });\n  res.end('Hello wtfnode!\\n');\n});\n\nserver.listen(3000, () => {\n  console.log('HTTP server listening on port 3000.');\n});\n\n// Register SIGINT handler to dump handles before exiting\nprocess.on('SIGINT', () => {\n  console.log('\\n[WTF Node?] Dumping open handles:');\n  wtf.dump();\n  // To allow clean exit after dump (optional, depending on desired behavior)\n  clearInterval(intervalId);\n  server.close(() => {\n    console.log('Server closed. Exiting process.');\n    process.exit(0);\n  });\n});\n\nconsole.log('Application running. Check http://localhost:3000 and wait for intervals.');","lang":"javascript","description":"Demonstrates module usage by setting up a `setInterval` and an HTTP server, then using `wtf.dump()` to report open handles when the process receives a SIGINT signal."},"warnings":[{"fix":"Manually inspect the provided source line and context to identify the original function or module creating the timer.","message":"When `wtfnode` reports on timers, the function name may appear as `wrapper` instead of the original function name. This is a limitation due to how `setInterval` and `setTimeout` create internal wrappers.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Investigate the parent process that spawned the current application to understand why the IPC channel remains open.","message":"The `IPC channel to parent` handle provides limited information if your program is spawned by another process (e.g., `child_process.fork`, PM2). `wtfnode` cannot extract more context as it's not based on code executed within the current program.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Press Ctrl+C twice to force-terminate processes stuck in infinite loops when using `wtfnode` globally. For module usage, ensure your SIGINT handler allows for `wtf.dump()` to complete and the process to exit.","message":"In version 0.4.0, a change was introduced for command-line usage (`wtfnode <yourscript>`). If the target script binds SIGINT and enters an infinite loop, Node.js might not exit. `wtfnode` now uses a watchdog proxy, allowing two Ctrl+C presses to force termination, though no output will be available.","severity":"breaking","affected_versions":">=0.4.0"},{"fix":"This warning can typically be ignored. If persistent, try delaying the call to `wtf.dump()` slightly within the child process.","message":"When using `wtfnode` from a child process on Node.js version 0.12, you might briefly see an `unable to determine callsite` warning due to transient child process handles. This is generally harmless.","severity":"gotcha","affected_versions":"=0.12.x"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Add `wtfnode` to your application and call `wtf.dump()` when you suspect the process should exit (e.g., on `SIGINT` or at the end of a long-running task) to identify the specific open handles.","cause":"One or more event loop handles (e.g., timers, network connections, open file descriptors) are still active, preventing Node.js from shutting down.","error":"Process never exits / Application hangs indefinitely"},{"fix":"Examine the `module.js:Line` indicated in the output. This line points to where the timer was originally set. Ensure all long-running timers are explicitly cleared when no longer needed using `clearInterval()` or `clearTimeout()`.","cause":"An `setInterval` or `setTimeout` call is still active, reported as a generic `wrapper` function.","error":"WTF Node? open handles: Timers: - (Xms ~ Ys) wrapper @ /path/to/module.js:Line"},{"fix":"Locate the code at `/path/to/connection.js:Line` to identify the socket's origin. Ensure all database connections, HTTP servers, or other network resources are explicitly closed or terminated when your application is done with them.","cause":"An open network socket or server connection is preventing the process from exiting. The listener shows where the connection handler was defined.","error":"WTF Node? open handles: Sockets: - A.B.C.D:PORT -> W.X.Y.Z:PORT Listeners: connect: anonymous @ /path/to/connection.js:Line"}],"ecosystem":"npm"}