jestjs/jest · error · TypeError
Cannot spy on the ${propertyKey} property because it is not
Error message
Cannot spy on the ${propertyKey} property because it is not a function; ${typeOfOriginal} given instead. What it means
Thrown as a TypeError by _spyOnProperty when the requested accessor exists but its value is not a function (and not already a mock). Accessors themselves must be functions to be spied on; a property defined with get: undefined or get: 42 trips this. Like error 146, the message suggests jest.replaceProperty for non-object values.
Source
Thrown at packages/jest-mock/src/index.ts:1411
if (!descriptor.configurable) {
throw new Error(
`Property \`${String(propertyKey)}\` is not declared configurable`,
);
}
if (!descriptor[accessType]) {
throw new Error(
`Property \`${String(
propertyKey,
)}\` does not have access type ${accessType}`,
);
}
const original = descriptor[accessType];
if (!this.isMockFunction(original)) {
if (typeof original !== 'function') {
throw new TypeError(
`Cannot spy on the ${String(
propertyKey,
)} property because it is not a function; ${this._typeOf(
original,
)} given instead.${
typeof original === 'object'
? ''
: ` If you are trying to mock a property, use \`jest.replaceProperty(object, '${String(
propertyKey,
)}', value)\` instead.`
}`,
);
}
descriptor[accessType] = this._makeComponent({type: 'function'}, () => {
if (isPropertyOwner) {
// @ts-expect-error: mock is assignable
descriptor![accessType] = original;View on GitHub (pinned to f49721c78e)
Solutions
- Inspect the descriptor and confirm the accessor is a function: const d = Object.getOwnPropertyDescriptor(obj, key); assert(typeof d.get === 'function').
- Repair the descriptor to use a real function before spying.
- If you actually want to replace the accessor's return value, use replaceProperty only if there is no getter, otherwise spyOn(..., 'get').mockReturnValue(value).
Example fix
// before
jest.spyOn(obj, 'key', 'get'); // obj.key get is undefined
// after
Object.defineProperty(obj, 'key', { configurable: true, get: () => 1 });
jest.spyOn(obj, 'key', 'get'); Defensive patterns
Strategy: validation
Validate before calling
const d = Object.getOwnPropertyDescriptor(obj, key);
if (!d || typeof d[accessType] !== 'function') {
throw new Error(`accessor '${String(key)}' ${accessType} is not a function`);
}
jest.spyOn(obj, key, accessType); Type guard
const accessorIsFunction = (o: object, k: PropertyKey, t: 'get' | 'set') => {
let d = Object.getOwnPropertyDescriptor(o, k);
let p = Object.getPrototypeOf(o);
while (!d && p) { d = Object.getOwnPropertyDescriptor(p, k); p = Object.getPrototypeOf(p); }
return !!(d && typeof d[t] === 'function');
};
if (accessorIsFunction(obj, key, 'get')) {
jest.spyOn(obj, key, 'get');
} Prevention
- Audit any test setup that calls Object.defineProperty to ensure accessors are functions.
- After build transforms, confirm getters/setters survived as functions.
- Re-validate descriptors after library upgrades.
When it happens
Trigger: An object with a property defined as { get: undefined, configurable: true } and you call jest.spyOn(obj, 'key', 'get'); a getter that has been overwritten with a non-function value; corrupted prototype where the accessor slot holds a primitive.
Common situations: Manual Object.defineProperty misuse in production or test setup that set get to a non-function; a build step that stripped/transformed a getter incorrectly; test helper that mutates descriptors.
Related errors
- Cannot use spyOn on a primitive value; ${typeOfObject} given
- Cannot spy on the `${methodKey}` property because it is not
- Property `${propertyKey}` does not exist in the provided obj
- Property `${propertyKey}` is not declared configurable
- Property `${propertyKey}` does not have access type ${access
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/fbe2ad598e95d17c.json.
Report an issue: GitHub.