# @sentry/node-native-stacktrace

> A native Node.js module that can capture JavaScript stack traces from main and worker threads, even with blocked event loops.

Latest version **0.5.2** (published 2026-07-28) · MIT license · 0 weekly downloads

## Install

```sh
npm install @sentry/node-native-stacktrace
pnpm add @sentry/node-native-stacktrace
yarn add @sentry/node-native-stacktrace
bun add @sentry/node-native-stacktrace
```

## Health

**Score 65/100 (B)** — status: active.

Positive: has types; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads; no esm support; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.5.2 |
| Published | 2026-07-28 |
| First published | 2026-06-08 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Node | >=18 |
| Dependencies | 2 |
| Unpacked size | 4.1 MB |
| Known vulnerabilities | 0 |
| Install scripts | yes |
| GitHub stars | 5 |
| Author | Sentry |
| Maintainers | sentry-bot |
| Keywords | stacktrace, native, nodejs, worker, sentry |

## Links

- npm: https://www.npmjs.com/package/@sentry/node-native-stacktrace
- Repository: https://github.com/getsentry/sentry-javascript-node-native-stacktrace
- Issues: https://github.com/getsentry/sentry-javascript-node-native-stacktrace/issues
- npm.io page: https://npm.io/package/@sentry/node-native-stacktrace

## Dependencies (2)

- [node-abi](https://npm.io/package/node-abi.md) ^3.89.0
- [detect-libc](https://npm.io/package/detect-libc.md) ^2.0.4

## Alternatives

- [@sentry/react-native](https://npm.io/package/@sentry/react-native.md) — 2.6M weekly downloads
- [@ardatan/aggregate-error](https://npm.io/package/@ardatan/aggregate-error.md) — 708.1K weekly downloads
- [custom-error-generator](https://npm.io/package/custom-error-generator.md) — 2.0K weekly downloads
- [@technik-sde/prosemirror-recreate-transform](https://npm.io/package/@technik-sde/prosemirror-recreate-transform.md) — 1.5K weekly downloads
- [@suchipi/error-utils](https://npm.io/package/@suchipi/error-utils.md) — 78 weekly downloads

## Recent versions

- 0.5.2 (latest) — 2026-07-28
- 0.5.1 — 2026-06-08

## README

# `@sentry/node-native-stacktrace`

A native Node.js module that can capture JavaScript stack traces for registered
main or worker threads from any other thread, even if event loops are blocked.

The module also provides a means to create a watchdog system to track event loop
blocking via periodic heartbeats. When the time from the last heartbeat crosses
a threshold, JavaScript stack traces can be captured.

For Node.js >= v24, this module can also capture state from `AsyncLocalStorage`
at the time of stack trace capture, which can help provide context on what the
thread was working on when it became blocked.

This native module is used for Sentry's
[Event Loop Blocked Detection](https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/event-loop-block/)
feature.

## Basic Usage

### 1. Register threads you want to monitor

In your main thread or worker threads:

```ts
import { registerThread } from "@sentry/node-native-stacktrace";

// Register this thread for monitoring
registerThread();
```

### 2. Capture stack traces from any thread

```ts
import { captureStackTrace } from "@sentry/node-native-stacktrace";

// Capture stack traces from all registered threads
const stacks = captureStackTrace();
console.log(stacks);
```

### Example Output

Stack traces show where each thread is currently executing:

```js
{
  '0': { // Main thread has ID '0'
    frames: [
      {
        function: 'from',
        filename: 'node:buffer',
        lineno: 298,
        colno: 28
      },
      {
        function: 'pbkdf2Sync',
        filename: 'node:internal/crypto/pbkdf2',
        lineno: 78,
        colno: 17
      },
      {
        function: 'longWork',
        filename: '/app/test.js',
        lineno: 20,
        colno: 29
      },
      {
        function: '?',
        filename: '/app/test.js',
        lineno: 24,
        colno: 1
      }
    ]
  },
  '2': { // Worker thread
    frames: [
      {
        function: 'from',
        filename: 'node:buffer',
        lineno: 298,
        colno: 28
      },
      {
        function: 'pbkdf2Sync',
        filename: 'node:internal/crypto/pbkdf2',
        lineno: 78,
        colno: 17
      },
      {
        function: 'longWork',
        filename: '/app/worker.js',
        lineno: 10,
        colno: 29
      },
      {
        function: '?',
        filename: '/app/worker.js',
        lineno: 14,
        colno: 1
      }
    ]
  }
}
```

## Advanced Usage: Automatic blocked event loop Detection

Set up automatic detection of blocked event loops:

### 1. Register threads with `AsyncLocalStorage` state tracking and heartbeats

Send regular heartbeats:

```ts
import {
  registerThread,
  threadPoll,
} from "@sentry/node-native-stacktrace";
import { AsyncLocalStorage } from "node:async_hooks";

// Create async local storage for state tracking
const asyncLocalStorage = new AsyncLocalStorage();
// Set some state in the async local storage
asyncLocalStorage.enterWith({ someState: "value" });

// Register this thread with async local storage
registerThread({ asyncLocalStorage });

// Send heartbeats every 200ms
setInterval(() => {
  threadPoll();
}, 200);
```

### 2. Monitor from a watchdog thread

Monitor all registered threads from a dedicated thread:

```ts
import {
  captureStackTrace,
  getThreadsLastSeen,
} from "@sentry/node-native-stacktrace";

const THRESHOLD = 1000; // 1 second

setInterval(() => {
  const threadsLastSeen = getThreadsLastSeen();

  for (const [threadId, timeSinceLastSeen] of Object.entries(threadsLastSeen)) {
    if (timeSinceLastSeen > THRESHOLD) {
      // Thread appears to be blocked - capture diagnostics
      const stackTraces = captureStackTrace();
      const blockedThread = stackTraces[threadId];

      console.error(`🚨 Thread ${threadId} blocked for ${timeSinceLastSeen}ms`);
      console.error("Stack trace:", blockedThread.frames);
      console.error("Async state:", blockedThread.asyncState);
    }
  }
}, 500); // Check every 500ms
```

## API Reference

### Functions

#### `registerThread(threadName?: string): void`

#### `registerThread(asyncStorage: AsyncStorageArgs, threadName?: string): void`

Registers the current thread for stack trace capture. Must be called from each
thread you want to capture stack traces from.

- `threadName` (optional): Name for the thread. Defaults to the current thread
  ID.
- `asyncStorage` (optional): `AsyncStorageArgs` to fetch state from
  `AsyncLocalStorage` on stack trace capture.

```ts
type AsyncStorageArgs = {
  /** AsyncLocalStorage instance to fetch state from */
  asyncLocalStorage: AsyncLocalStorage<unknown>;
  /**
   * Optional array of keys to pick a specific property from the store.
   * Key will be traversed in order through Objects/Maps to reach the desired property.
   *
   * This is useful if you want to capture Open Telemetry context values as state.
   *
   * To get this value:
   * context.getValue(MY_UNIQUE_SYMBOL_REF)
   *
   * You would set:
   * stateLookup: ['_currentContext', MY_UNIQUE_SYMBOL_REF]
   */
  stateLookup?: Array<string | symbol>;
};
```

#### `captureStackTrace<State>(): Record<string, Thread<A, P>>`

Captures stack traces from all registered threads. Can be called from any thread
but will not capture a stack trace for the calling thread itself.

```ts
type Thread<A = unknown, P = unknown> = {
  frames: StackFrame[];
  /** State captured from the AsyncLocalStorage */
  asyncState?: A;
  /** Optional state provided when calling threadPoll */
  pollState?: P;
};

type StackFrame = {
  function: string;
  filename: string;
  lineno: number;
  colno: number;
};
```

#### `threadPoll<State>(disableLastSeen?: boolean, pollState?: object): void`

Sends a heartbeat from the current thread.

- `disableLastSeen` (optional): If `true`, disables the tracking of the last
  seen time for this thread.
- `pollState` (optional): An object containing state to include with the next
  stack trace capture. This can be used instead of or in addition to
  `AsyncLocalStorage` based state tracking.

#### `getThreadsLastSeen(): Record<string, number>`

Returns the time in milliseconds since each registered thread called
`threadPoll()`.

---
_Source: https://npm.io/package/@sentry/node-native-stacktrace · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
