jestjs/jest · error · Error
is not declared configurable
Error message
${propertyName} is not declared configurable What it means
Thrown by SpyRegistry._spyOnProperty when the property descriptor's configurable flag is false (spyRegistry.ts:177-181). Object.defineProperty can only redefine a property whose descriptor is configurable; a non-configurable property cannot be replaced with a spy.
Solutions
- Redefine the property as configurable before spying: Object.defineProperty(obj, 'p', { configurable: true, ...rest }).
- Spy on a wrapper module you control rather than the locked native object.
- Use jest.mock to replace the entire module instead of spying on a single locked property.
- If testing env accessors, copy needed values to a plain object and spy on that.
Example fix
// before
spyOn(globalThis, 'location', 'get'); // non-configurable
// after
jest.mock('./env', () => ({getLocation: () => '/fake'})); Defensive patterns
Strategy: validation
Validate before calling
const d = Object.getOwnPropertyDescriptor(obj, propertyName);
if (d && !d.configurable) {
throw new Error(`${String(propertyName)} is non-configurable; mock the module instead`);
}
spyOn(obj, propertyName, 'get'); Type guard
const isConfigurable = (o: object, k: PropertyKey): boolean => {
const d = Object.getOwnPropertyDescriptor(o, k);
return !!d && !!d.configurable;
}; Prevention
- Do not spy on native non-configurable accessors; mock the module instead.
- Redefine locked properties as configurable before spying.
- Spy on wrapper modules you control.
When it happens
Trigger: spyOn on a property defined via Object.defineProperty(obj, 'p', { configurable: false }), built-in prototype properties like Function.prototype.arguments, frozen object accessor properties, or sealed objects.
Common situations: Spying on built-ins (window.location, process.env accessors, native prototype members); library authors who deliberately lock properties; Object.seal/Object.freeze on the target; spying on class private fields compiled to non-configurable descriptors.
Related errors
- Property does not have access type
- has already been spied upon
- : could not find an object to spy upon for Usage: spyOn( , )
- : is not declared writable or has no setter Usage: spyOn( …
- : No property name supplied Usage: spyOn( , )
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/47cddda507bbe05e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/jest-jasmine2/src/jasmine/spyRegistry.ts:178
}
if (!propertyName) {
throw new Error(getErrorMsg('No property name supplied'));
}
let descriptor: PropertyDescriptor | undefined;
try {
descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
} catch {
// IE 8 doesn't support `definePropery` on non-DOM nodes
}
if (!descriptor) {
throw new Error(getErrorMsg(`${propertyName} property does not exist`));
}
if (!descriptor.configurable) {
throw new Error(
getErrorMsg(`${propertyName} is not declared configurable`),
);
}
if (!descriptor[accessType]) {
throw new Error(
getErrorMsg(
`Property ${propertyName} does not have access type ${accessType}`,
),
);
}
if (obj[propertyName] && isSpy(obj[propertyName])) {
if (this.respy) {
return obj[propertyName];
} else {
throw new Error(
getErrorMsg(`${propertyName} has already been spied upon`),View on GitHub (pinned to 8e6d128e4a)