{"record":{"id":"879d6f24edbb2b98","repo":"jestjs/jest","slug":"spyon-propertyname-property-does-not-exist","errorCode":null,"errorMessage":"<spyOn> : ${propertyName} property does not exist\nUsage: spyOn(<object>, <methodName>)","messagePattern":"<spyOn> : (.+?) property does not exist\nUsage: spyOn\\(<object>, <methodName>\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-jasmine2/src/jasmine/spyRegistry.ts","lineNumber":174,"sourceCode":"          getErrorMsg(\n            `could not find an object to spy upon for ${propertyName}`,\n          ),\n        );\n      }\n\n      if (!propertyName) {\n        throw new Error(getErrorMsg('No property name supplied'));\n      }\n\n      let descriptor: PropertyDescriptor | undefined;\n      try {\n        descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);\n      } catch {\n        // IE 8 doesn't support `definePropery` on non-DOM nodes\n      }\n\n      if (!descriptor) {\n        throw new Error(getErrorMsg(`${propertyName} property does not exist`));\n      }\n\n      if (!descriptor.configurable) {\n        throw new Error(\n          getErrorMsg(`${propertyName} is not declared configurable`),\n        );\n      }\n\n      if (!descriptor[accessType]) {\n        throw new Error(\n          getErrorMsg(\n            `Property ${propertyName} does not have access type ${accessType}`,\n          ),\n        );\n      }\n\n      if (obj[propertyName] && isSpy(obj[propertyName])) {\n        if (this.respy) {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-jasmine2/src/jasmine/spyRegistry.ts#L156-L192","documentation":"Thrown by SpyRegistry._spyOnProperty when no property descriptor is found for the named property (spyRegistry.ts:173-175). Property spying redefines the descriptor via Object.defineProperty, so a property with no existing accessor cannot be spied through the access-type path.","triggerScenarios":"spyOn(obj, 'missingProp', 'get') where the property does not exist on obj or its prototype chain, or spying on a plain data field (no getter) via the 'get' access type.","commonSituations":"Renamed property after a library upgrade; spying on a getter that is defined on a subclass while spying on the parent instance; prototype-only getters where the lookup at the instance level returns undefined; typos in property names.","solutions":["Verify the descriptor exists: console.log(Object.getOwnPropertyDescriptor(obj, 'prop')).","Spy on the correct object in the chain (prototype vs instance).","Use the plain spyOn(obj, 'method') form for data fields rather than the property-access form.","After a refactor, update the spy name to match the new property."],"exampleFix":"// before\nspyOn(store, 'cache', 'get'); // cache is a plain field, no getter\n// after\nspyOn(store, 'cache'); // or define a getter first","handlingStrategy":"validation","validationCode":"if (!Object.getOwnPropertyDescriptor(obj, propertyName)) {\n  throw new Error(`spyOn property: ${propertyName} has no descriptor on the target`);\n}\nspyOn(obj, propertyName, 'get');","typeGuard":"const hasPropertyDescriptor = (o: object, k: PropertyKey): boolean =>\n  Object.getOwnPropertyDescriptor(o, k) !== undefined;","tryCatchPattern":null,"preventionTips":["Inspect the descriptor before spying.","Spy on the correct prototype chain level.","Use plain spyOn for data fields."],"tags":["jest","spyon","mocking","property-accessor","missing-property","api-misuse"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}