jestjs/jest · error · TypeError

Primitives cannot leak memory. You passed a ${typeof value}:

Error message

Primitives cannot leak memory. You passed a ${typeof value}: <${prettyFormat(value)}>

What it means

Thrown by the `LeakDetector` constructor in jest-leak-detector/index.ts:28 when the value passed is a primitive (`isPrimitive(value)` true). Leak detection relies on a `FinalizationRegistry` weakly tracking an object; primitives are passed by value and cannot hold a strong reference, so tracking them is meaningless and the constructor rejects them with a TypeError.

Source

Thrown at packages/jest-leak-detector/src/index.ts:28

import {getHeapSnapshot, setFlagsFromString} from 'node:v8';
import {runInNewContext} from 'node:vm';
import {isPrimitive} from '@jest/get-type';
import {format as prettyFormat} from 'pretty-format';

interface LeakDetectorOptions {
  shouldGenerateV8HeapSnapshot: boolean;
}

const tick = promisify(setImmediate);

export default class LeakDetector {
  private _isReferenceBeingHeld: boolean;
  private _shouldGenerateV8HeapSnapshot: boolean;
  private readonly _finalizationRegistry?: FinalizationRegistry<undefined>;

  constructor(value: unknown, opt?: LeakDetectorOptions) {
    if (isPrimitive(value)) {
      throw new TypeError(
        [
          'Primitives cannot leak memory.',
          `You passed a ${typeof value}: <${prettyFormat(value)}>`,
        ].join(' '),
      );
    }

    // When `_finalizationRegistry` is GCed the callback we set will no longer be called,
    this._finalizationRegistry = new FinalizationRegistry(() => {
      this._isReferenceBeingHeld = false;
    });
    this._finalizationRegistry.register(value as object, undefined);

    this._isReferenceBeingHeld = true;

    this._shouldGenerateV8HeapSnapshot =
      opt?.shouldGenerateV8HeapSnapshot ?? true;

View on GitHub (pinned to f49721c78e)

Solutions

  1. Pass an object/function/array instead of a primitive.
  2. If the value is logically a primitive, skip leak detection for that test (it cannot leak by definition).
  3. Wrap the primitive in an object only if you genuinely need to detect references to the wrapper.

Example fix

// before
new LeakDetector('config-value')
// after
new LeakDetector({ value: 'config-value' })
Defensive patterns

Strategy: type-guard

Validate before calling

import {isPrimitive} from '@jest/get-type';
if (isPrimitive(value)) { /* skip detection, primitives can't leak */ return; }
new LeakDetector(value);

Type guard

const isTrackable = (v: unknown): v is object =>
  v != null && (typeof v === 'object' || typeof v === 'function');

Prevention

When it happens

Trigger: Constructing `new LeakDetector('foo')`, `new LeakDetector(42)`, `new LeakDetector(true)`, `new LeakDetector(null)`, `new LeakDetector(Symbol())`, or `new LeakDetector(0n)`. Most commonly hit indirectly when a test that uses `--detectLeaks` exports or returns a primitive as the module under test.

Common situations: Running Jest with `--detectOpenHandles`/`--detectLeaks` against a test module whose default export is a primitive (string/number); a leak-detector unit test that feeds a literal; wrapping a JSON config value.


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/3b4ea898a8b6a941.json. Report an issue: GitHub.