{"id":"47cddda507bbe05e","repo":"jestjs/jest","slug":"propertyname-is-not-declared-configurable","errorCode":null,"errorMessage":"${propertyName} is not declared configurable","messagePattern":"(.+?) is not declared configurable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-jasmine2/src/jasmine/spyRegistry.ts","lineNumber":178,"sourceCode":"      }\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) {\n          return obj[propertyName];\n        } else {\n          throw new Error(\n            getErrorMsg(`${propertyName} has already been spied upon`),","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-jasmine2/src/jasmine/spyRegistry.ts#L160-L196","documentation":"Thrown by `SpyRegistry._spyOnProperty` in spyRegistry.ts:178 when the descriptor's `configurable` flag is false. jasmine2 redefines the property with `Object.defineProperty`, which throws on non-configurable properties; this guard gives a clearer message first.","triggerScenarios":"Spying on a property defined with `configurable: false`, a non-configurable built-in (e.g. `window.location` props), or an object sealed/frozen with `Object.seal`/`Object.freeze`.","commonSituations":"Frozen config objects; sealed singletons; TS `readonly` fields compiled non-configurable; trying to spy on host-provided non-configurable globals.","solutions":["Make the property configurable in production code (`Object.defineProperty(obj, 'p', { configurable: true, ... })`).","Spy on the prototype if the instance property is non-configurable but the prototype property is configurable.","Refactor to inject the dependency so you do not need to redefine a frozen property."],"exampleFix":"// before\nspyOnProperty(frozenConfig, 'timeout', 'get') // non-configurable\n// after\n// make it configurable in the module under test, or inject the value\nspyOnProperty(Proto.prototype, 'timeout', 'get')","handlingStrategy":"validation","validationCode":"const d = Object.getOwnPropertyDescriptor(obj, propertyName);\nif (d && !d.configurable) { throw new Error(`${propertyName} is non-configurable`); }\nspyOnProperty(obj, propertyName, 'get');","typeGuard":"const isConfigurable = (o: object, p: string): boolean => {\n  const d = Object.getOwnPropertyDescriptor(o, p);\n  return !d || Boolean(d.configurable);\n};","tryCatchPattern":null,"preventionTips":["Define test-relevant properties as configurable: true.","Avoid Object.freeze/Object.seal on objects you need to spy on."],"tags":["jasmine2","spy","spy-on-property","non-configurable","frozen"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}