denoland/deno · error · TypeError

Cannot mock property '${String(methodName)}' because it is n

Error message

Cannot mock property '${String(methodName)}' because it is not a function

What it means

After finding the descriptor, mock.method() selects descriptor.value (or descriptor.get/descriptor.set when the getter/setter options are set) and requires it to be a function. A data property holding a non-function value, or a getter/setter flag that does not match the descriptor's kind (descriptor.get is undefined on a data property), throws this TypeError.

Source

Thrown at ext/node/polyfills/testing.ts:2516

    throw new TypeError(
      `Cannot mock property '${String(methodName)}' because it does not exist`,
    );
  }

  const isGetter = options?.getter ?? false;
  const isSetter = options?.setter ?? false;

  let original;
  if (isGetter) {
    original = descriptor.get;
  } else if (isSetter) {
    original = descriptor.set;
  } else {
    original = descriptor.value;
  }

  if (typeof original !== "function") {
    throw new TypeError(
      `Cannot mock property '${
        String(methodName)
      }' because it is not a function`,
    );
  }

  const restore = () => {
    ObjectDefineProperty(object, methodName, {
      __proto__: null,
      ...descriptor,
    });
  };

  const impl = implementation === undefined ? original : implementation;
  const ctx = new MockFunctionContext(impl, restore, options?.times);
  ArrayPrototypePush(activeMocks, ctx);

  const mockFn = createMockFunction(original, impl, ctx);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. For non-function values use mock.property(obj, 'id', 42) instead of mock.method
  2. Match the flag to the descriptor kind: { getter: true } only for accessors with a get, { setter: true } only with a set
  3. Inspect first: const d = Object.getOwnPropertyDescriptor(obj, 'id'); check typeof d.value / typeof d.get
  4. If both getter and setter exist, pass the flag matching the half you replace

Example fix

// before
mock.method(user, 'id', () => 42); // 'id' is a number, not a function

// after
mock.property(user, 'id', 42);
Defensive patterns

Strategy: validation

Validate before calling

const d = Object.getOwnPropertyDescriptor(obj, name);
const target = options?.getter ? d?.get : options?.setter ? d?.set : d?.value;
if (typeof target !== 'function') {
  // pick the right tool: property mock for values, method mock for functions
}

Type guard

function isMockableFn(o: object, k: PropertyKey): boolean {
  const v = (o as Record<PropertyKey, unknown>)[k];
  return typeof v === 'function';
}

Try / catch

try { mock.method(obj, name, impl, opts); } catch (e) { if (e instanceof TypeError && /not a function/.test(e.message)) { mock.property(obj, name, fallbackValue); } else throw e; }

Prevention

When it happens

Trigger: mock.method(user, 'id') where id is a number; mock.method(obj, 'value', impl, { getter: true }) when 'value' is a plain data property; { setter: true } against a getter-only accessor.

Common situations: Confusing value mocks with method mocks; assuming an API is an accessor when the implementation uses a plain field; version changes replacing a getter with a data field.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/74c4965b75517a7b. Report an issue: GitHub.