jestjs/jest · error · TypeError

Primitives cannot leak memory. You passed a

Error message

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

What it means

Thrown by jest-leak-detector's LeakDetector constructor when the value passed is a primitive (index.ts:27-34). Memory-leak detection relies on a FinalizationRegistry that only tracks object references; primitives (string, number, boolean, symbol, bigint, null, undefined) cannot be held by reference and therefore cannot leak, so the constructor refuses them.

Solutions

  1. Wrap the primitive in an object: new LeakDetector({value: primitive}).
  2. Verify the subject is an object before constructing: if (!isPrimitive(subject)) new LeakDetector(subject).
  3. If using --detect-leaks, ensure your exports are objects/classes, not bare primitives.
  4. Debug what value is being passed by logging typeof before constructing.

Example fix

// before
new LeakDetector(getToken()); // getToken() returns a string
// after
const token = getToken();
new LeakDetector({token}); // wrap in object
Defensive patterns

Strategy: type-guard

Validate before calling

import {isPrimitive} from '@jest/get-type';
if (isPrimitive(value)) {
  throw new TypeError('LeakDetector requires an object reference, not a primitive');
}
new LeakDetector(value);

Type guard

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

Prevention

When it happens

Trigger: new LeakDetector(42), new LeakDetector('hello'), new LeakDetector(null), or new LeakDetector(true). Also when a value that is expected to be an object turns out to be a primitive at runtime (e.g. a function returned a string instead of an instance).

Common situations: Writing custom leak tests and passing a config value instead of the instance; jest-jasmine2 leak detection enabled (--detect-leaks) on a test whose subject is a primitive; helper functions that lose object-ness via serialisation; API change where a factory now returns a primitive token.

Related errors


AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10). Data as JSON: /api/errors/3b4ea898a8b6a941. Report an issue: GitHub.

Appendix: 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 8e6d128e4a)