jestjs/jest · error · Error

Property `${propertyKey}` does not have access type ${access

Error message

Property `${propertyKey}` does not have access type ${accessType}

What it means

Thrown by _spyOnProperty when the descriptor exists and is configurable but lacks the requested accessType — i.e. you asked to spy 'get' on a write-only accessor (only has set), or 'set' on a read-only accessor (only has get). The check is !descriptor[accessType].

Source

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

      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[accessType]) {
      throw new Error(
        `Property \`${String(
          propertyKey,
        )}\` does not have access type ${accessType}`,
      );
    }

    const original = descriptor[accessType];

    if (!this.isMockFunction(original)) {
      if (typeof original !== 'function') {
        throw new TypeError(
          `Cannot spy on the ${String(
            propertyKey,
          )} property because it is not a function; ${this._typeOf(
            original,
          )} given instead.${
            typeof original === 'object'
              ? ''

View on GitHub (pinned to f49721c78e)

Solutions

  1. Spy on the access type the property actually defines: use 'get' for read-only, 'set' for write-only.
  2. Inspect the descriptor first: Object.getOwnPropertyDescriptor(obj, key) and check which of get/set are present.
  3. If you need to control both directions, redefine the property (if configurable) to have both, then spy on each.

Example fix

// before
jest.spyOn(user, 'id', 'set'); // id is read-only
// after
jest.spyOn(user, 'id', 'get');
Defensive patterns

Strategy: validation

Validate before calling

const d = Object.getOwnPropertyDescriptor(obj, key);
if (!d || !d['get']) {
  throw new Error(`'${String(key)}' has no getter; cannot spy with 'get'`);
}
jest.spyOn(obj, key, 'get');

Type guard

const hasAccessType = (o: object, k: PropertyKey, t: 'get' | 'set'): boolean => {
  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[t] === 'function');
};

const access = hasAccessType(obj, key, 'get') ? 'get' : 'set';
jest.spyOn(obj, key, access);

Prevention

When it happens

Trigger: jest.spyOn(obj, 'readOnlyProp', 'set') where the property has only a getter; jest.spyOn(obj, 'writeOnlyProp', 'get') where it has only a setter. Common with computed properties that intentionally expose only one direction.

Common situations: Assuming every accessor is a full get/set pair; library design where a property is intentionally write-only (e.g. credentials) or read-only.

Related errors


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