jestjs/jest · error · TypeError

Cannot spy on the `${String(methodKey)}` property because it

Error message

Cannot spy on the `${String(methodKey)}` property because it is not a function; ${this._typeOf(original)} given instead.${typeof original === 'object' ? '' : ` If you are trying to mock a property, use `jest.replaceProperty(object, '${String(methodKey)}', value)` instead.`}

What it means

Thrown by jest.spyOn (as a TypeError) when the property exists but is not a function. spyOn only wraps functions; for value properties the message actively suggests jest.replaceProperty. The replaceProperty hint is suppressed when the original is an object.

Source

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

    }

    if (accessType) {
      return this._spyOnProperty(object, methodKey, accessType);
    }

    const original = object[methodKey];

    if (!original) {
      throw new Error(
        `Property \`${String(
          methodKey,
        )}\` does not exist in the provided object`,
      );
    }

    if (!this.isMockFunction(original)) {
      if (typeof original !== 'function') {
        throw new TypeError(
          `Cannot spy on the \`${String(
            methodKey,
          )}\` property because it is not a function; ${this._typeOf(
            original,
          )} given instead.${
            typeof original === 'object'
              ? ''
              : ` If you are trying to mock a property, use \`jest.replaceProperty(object, '${String(
                  methodKey,
                )}', value)\` instead.`
          }`,
        );
      }

      const isMethodOwner = Object.prototype.hasOwnProperty.call(
        object,
        methodKey,
      );

View on GitHub (pinned to 8e6d128e4a)

Solutions

  1. Use jest.replaceProperty(obj,'count',5) for value properties.
  2. If the property is backed by a getter, call jest.spyOn(obj,'prop','get').mockReturnValue(value).
  3. Confirm via typeof obj.method === 'function' before spying.

Example fix

// before
jest.spyOn(config, 'timeout'); // timeout is a number
// after
jest.replaceProperty(config, 'timeout', 1000);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof obj[methodKey] !== 'function') {
  // value property -> use replaceProperty
  jest.replaceProperty(obj, methodKey, value);
} else {
  jest.spyOn(obj, methodKey);
}

Type guard

const isMethod = <T extends object>(o: T, k: keyof T): boolean =>
  typeof o[k] === 'function';

Prevention

When it happens

Trigger: jest.spyOn(obj,'count') when obj.count = 5; jest.spyOn(config,'timeout') when timeout is a number; jest.spyOn(obj,'items') when items is an array.

Common situations: Confusing a data property with a method; the API changed and a method became a value; trying to spy on a getter-backed value without the 'get' access type.

Related errors


AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10). Data as JSON: /api/errors/58263617c402be61. Report an issue: GitHub.