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
- Wrap the primitive in an object: new LeakDetector({value: primitive}).
- Verify the subject is an object before constructing: if (!isPrimitive(subject)) new LeakDetector(subject).
- If using --detect-leaks, ensure your exports are objects/classes, not bare primitives.
- 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
- Wrap primitives in objects before leak-detecting.
- Confirm the factory returns an instance, not a token.
- Guard with isPrimitive before constructing.
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
- path must be a string or array
- value must be a function
- value must be a non-null object
- value must be a number
- value must be a string if value is a string
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)