{"id":"79c77b3eac6709d4","repo":"jestjs/jest","slug":"cannot-spy-on-the-methodkey-property-because","errorCode":null,"errorMessage":"Cannot spy on the `${methodKey}` 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":1305,"sourceCode":"    }\n\n    if (accessType) {\n      return this._spyOnProperty(object, methodKey, accessType);\n    }\n\n    const original = object[methodKey];\n\n    if (!original) {\n      throw new Error(\n        `Property \\`${String(\n          methodKey,\n        )}\\` does not exist in the provided object`,\n      );\n    }\n\n    if (!this.isMockFunction(original)) {\n      if (typeof original !== 'function') {\n        throw new TypeError(\n          `Cannot spy on the \\`${String(\n            methodKey,\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                  methodKey,\n                )}', value)\\` instead.`\n          }`,\n        );\n      }\n\n      const isMethodOwner = Object.prototype.hasOwnProperty.call(\n        object,\n        methodKey,\n      );","sourceCodeStart":1287,"sourceCodeEnd":1323,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-mock/src/index.ts#L1287-L1323","documentation":"Thrown as a TypeError by jest.spyOn when object[methodKey] exists and is truthy but typeof original !== 'function' (and it is not already a mock). spyOn only works on methods; for value properties you must use replaceProperty. The message is helpful: it names the actual type found and, for non-object values, suggests jest.replaceProperty(object, 'key', value) instead.","triggerScenarios":"jest.spyOn(config, 'port') where config.port = 3000; jest.spyOn(user, 'name') where name is a string; jest.spyOn(arr, 'length') (length is a number); jest.spyOn(obj, 'list') where list is an array. The mocker refuses to wrap a non-function because there is no invocation to intercept.","commonSituations":"Confusing a property that holds data with a method that returns data; using spyOn where replaceProperty is the right tool; spying on a field whose value changed from a function to a constant after a refactor.","solutions":["Use jest.replaceProperty(object, 'key', value) for value properties, then restore with .restore().","If the property should be a method, fix the producer so it actually assigns a function.","If you meant to intercept a getter, call jest.spyOn(object, 'key', 'get')."],"exampleFix":"// before\njest.spyOn(config, 'port'); // port is 3000\n// after\njest.replaceProperty(config, 'port', 8080);","handlingStrategy":"type-guard","validationCode":"if (typeof obj[methodKey] !== 'function') {\n  // It's a value property -> use replaceProperty\n  jest.replaceProperty(obj, methodKey, newValue);\n} else {\n  jest.spyOn(obj, methodKey);\n}","typeGuard":"const isMethod = <T extends object, K extends keyof T>(o: T, k: K): o is T & Record<K, (...a: any[]) => any> =>\n  typeof o[k] === 'function';\n\nif (isMethod(obj, 'port')) {\n  jest.spyOn(obj, 'port');\n} else {\n  jest.replaceProperty(obj, 'port', 8080);\n}","tryCatchPattern":null,"preventionTips":["Use replaceProperty for data, spyOn for methods.","When refactoring a property from function to value, update tests immediately.","Inspect typeof obj.key before deciding which API to call."],"tags":["jest-mock","spyon","type-error","replaceproperty"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}