jestjs/jest · error · TypeError
Cannot spy on the ${String(propertyKey)} property because it
Error message
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.`} What it means
Thrown by _spyOnProperty (as a TypeError) when the located accessor is truthy but typeof !== 'function' (and not already a mock). Per the JS spec a descriptor's get/set are function or undefined, so reaching this branch implies a manually corrupted/tampered descriptor. It is a defensive guard; the message also suggests jest.replaceProperty for non-object originals.
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 8e6d128e4a)
Solutions
- Inspect Object.getOwnPropertyDescriptor(obj, key) and confirm get/set are functions.
- Remove any code that mutates descriptors in a non-standard way.
- Restore the property via Object.defineProperty with a proper function accessor before spying.
Example fix
// before (descriptor tampered)
Object.defineProperty(obj, 'x', {get: 42 as any, configurable: true});
jest.spyOn(obj, 'x', 'get');
// after
Object.defineProperty(obj, 'x', {get: () => 42, configurable: true});
jest.spyOn(obj, 'x', 'get'); Defensive patterns
Strategy: validation
Validate before calling
const d = Object.getOwnPropertyDescriptor(obj, propertyKey);
if (!d || typeof d[accessType] !== 'function') {
throw new Error(`${String(propertyKey)} ${accessType} accessor is not a function`);
}
jest.spyOn(obj, propertyKey, accessType); Type guard
const accessorIsFunction = (o: object, k: PropertyKey, a: 'get' | 'set'): boolean => {
const d = Object.getOwnPropertyDescriptor(o, k);
return !!d && typeof d[a] === 'function';
}; Prevention
- Never mutate descriptors to non-function values.
- Audit any third-party code that redefines accessors.
- If a Proxy is involved, log the descriptor it returns.
When it happens
Trigger: Manually assigning descriptor.get = 'notAFunction'; a custom Proxy returning a malformed descriptor; a third-party library mutating descriptors in a non-standard way.
Common situations: Extremely rare; only appears with non-standard descriptor manipulation or exotic Proxy traps. Normal code never hits this.
Related errors
- Property `${String(propertyKey)}` does not exist in the prov
- Property `${String(propertyKey)}` is not declared configurab
- Property `${String(propertyKey)}` does not have access type
- ${RECEIVED_COLOR('received')} value must be a mock or spy fu
- ${RECEIVED_COLOR('received')} value must be a mock function
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/c752f9aafdba360d.
Report an issue: GitHub.