jestjs/jest · error · Error

Cannot replace the `${propertyKey}` property because it has

Error message

Cannot replace the `${propertyKey}` property because it has a getter. Use `jest.spyOn(object, '${propertyKey}', 'get').mockReturnValue(value)` instead.

What it means

Thrown by jest.replaceProperty when the descriptor has a getter (descriptor.get !== undefined). replaceProperty only handles data properties; replacing an accessor's value would silently lose the getter. The message tells you the correct tool: jest.spyOn(object, 'key', 'get').mockReturnValue(value).

Source

Thrown at packages/jest-mock/src/index.ts:1490

    while (!descriptor && proto !== null) {
      descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
      proto = Object.getPrototypeOf(proto);
    }
    if (!descriptor) {
      throw new Error(
        `Property \`${String(
          propertyKey,
        )}\` does not exist in the provided object`,
      );
    }
    if (!descriptor.configurable) {
      throw new Error(
        `Property \`${String(propertyKey)}\` is not declared configurable`,
      );
    }

    if (descriptor.get !== undefined) {
      throw new Error(
        `Cannot replace the \`${String(
          propertyKey,
        )}\` property because it has a getter. Use \`jest.spyOn(object, '${String(
          propertyKey,
        )}', 'get').mockReturnValue(value)\` instead.`,
      );
    }

    if (descriptor.set !== undefined) {
      throw new Error(
        `Cannot replace the \`${String(
          propertyKey,
        )}\` property because it has a setter. Use \`jest.spyOn(object, '${String(
          propertyKey,
        )}', 'set').mockReturnValue(value)\` instead.`,
      );
    }

View on GitHub (pinned to f49721c78e)

Solutions

  1. Follow the message: const spy = jest.spyOn(object, 'key', 'get'); spy.mockReturnValue(value); and spy.mockRestore() after.
  2. If you need to truly replace the descriptor, redefine it first with Object.defineProperty to remove the getter, then use replaceProperty (only if configurable).
  3. Prefer the spyOn path — it restores cleanly.

Example fix

// before
jest.replaceProperty(store, 'count', 5); // count has a getter
// after
const spy = jest.spyOn(store, 'count', 'get').mockReturnValue(5);
// ... in afterEach: spy.mockRestore();
Defensive patterns

Strategy: validation

Validate before calling

const d = Object.getOwnPropertyDescriptor(obj, key) ?? Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), key);
if (d && d.get) {
  // use spyOn 'get' instead
  const spy = jest.spyOn(obj, key, 'get').mockReturnValue(value);
} else {
  jest.replaceProperty(obj, key, value);
}

Type guard

const isGetterProp = (o: object, k: PropertyKey) => {
  let d = Object.getOwnPropertyDescriptor(o, k);
  let p = Object.getPrototypeOf(o);
  while (!d && p) { d = Object.getOwnPropertyDescriptor(p, k); p = Object.getPrototypeOf(p); }
  return !!(d && typeof d.get === 'function');
};

if (isGetterProp(obj, key)) {
  jest.spyOn(obj, key, 'get').mockReturnValue(value);
} else {
  jest.replaceProperty(obj, key, value);
}

Prevention

When it happens

Trigger: jest.replaceProperty(store, 'count', 5) where count is defined with a get accessor; replacing a class field declared with get; a library that exposes computed read-only properties.

Common situations: Modern class syntax using get x() {...} that looks like a data field; refactoring a value property into a computed getter without updating tests; libraries (MobX, Vue) that back properties with getters.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/1d7aed5ee9253d31.json. Report an issue: GitHub.