{"id":"fbe2ad598e95d17c","repo":"jestjs/jest","slug":"cannot-spy-on-the-propertykey-property-because","errorCode":null,"errorMessage":"Cannot spy on the ${propertyKey} property because it is not a function; ${typeOfOriginal} given instead.","messagePattern":"Cannot spy on the (.+?) property because it is not a function; (.+?) given instead\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/jest-mock/src/index.ts","lineNumber":1411,"sourceCode":"    if (!descriptor.configurable) {\n      throw new Error(\n        `Property \\`${String(propertyKey)}\\` is not declared configurable`,\n      );\n    }\n\n    if (!descriptor[accessType]) {\n      throw new Error(\n        `Property \\`${String(\n          propertyKey,\n        )}\\` does not have access type ${accessType}`,\n      );\n    }\n\n    const original = descriptor[accessType];\n\n    if (!this.isMockFunction(original)) {\n      if (typeof original !== 'function') {\n        throw new TypeError(\n          `Cannot spy on the ${String(\n            propertyKey,\n          )} property because it is not a function; ${this._typeOf(\n            original,\n          )} given instead.${\n            typeof original === 'object'\n              ? ''\n              : ` If you are trying to mock a property, use \\`jest.replaceProperty(object, '${String(\n                  propertyKey,\n                )}', value)\\` instead.`\n          }`,\n        );\n      }\n\n      descriptor[accessType] = this._makeComponent({type: 'function'}, () => {\n        if (isPropertyOwner) {\n          // @ts-expect-error: mock is assignable\n          descriptor![accessType] = original;","sourceCodeStart":1393,"sourceCodeEnd":1429,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-mock/src/index.ts#L1393-L1429","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\njest.spyOn(obj, 'key', 'get'); // obj.key get is undefined\n// after\nObject.defineProperty(obj, 'key', { configurable: true, get: () => 1 });\njest.spyOn(obj, 'key', 'get');","handlingStrategy":"validation","validationCode":"const d = Object.getOwnPropertyDescriptor(obj, key);\nif (!d || typeof d[accessType] !== 'function') {\n  throw new Error(`accessor '${String(key)}' ${accessType} is not a function`);\n}\njest.spyOn(obj, key, accessType);","typeGuard":"const accessorIsFunction = (o: object, k: PropertyKey, t: 'get' | 'set') => {\n  let d = Object.getOwnPropertyDescriptor(o, k);\n  let p = Object.getPrototypeOf(o);\n  while (!d && p) { d = Object.getOwnPropertyDescriptor(p, k); p = Object.getPrototypeOf(p); }\n  return !!(d && typeof d[t] === 'function');\n};\n\nif (accessorIsFunction(obj, key, 'get')) {\n  jest.spyOn(obj, key, 'get');\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["jest-mock","spyon","accessor","type-error"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}