vitest-dev/vitest · error · TypeError

.toHaveProperty() expects to receive a valid object, but got

Error message

.toHaveProperty() expects to receive a valid object, but got ${actual}

What it means

Thrown by the `toHaveProperty` matcher when the value passed to `expect()` is `null` or `undefined`. The matcher needs a real object to look up a property path on, so it refuses to operate on a missing receiver. This is a hard `TypeError` raised before any property lookup is attempted.

Source

Thrown at packages/expect/src/jest-expect.ts:471

  def('toBeInstanceOf', function (obj: any) {
    return this.instanceOf(obj)
  })
  def('toHaveLength', function (length: number) {
    return this.have.length(length)
  })
  // destructuring, because it checks `arguments` inside, and value is passing as `undefined`
  def(
    'toHaveProperty',
    function (...args: [property: string | (string | number)[], value?: any]) {
      if (Array.isArray(args[0])) {
        args[0] = args[0]
          .map(key => String(key).replace(/([.[\]])/g, '\\$1'))
          .join('.')
      }

      const actual = this._obj as any
      if (actual == null) {
        throw new TypeError(
          `.toHaveProperty() expects to receive a valid object, but got ${actual}`,
        )
      }
      const [propertyName, expected] = args
      const getValue = () => {
        const hasOwn = Object.hasOwn(
          actual,
          propertyName,
        )
        if (hasOwn) {
          return { value: actual[propertyName], exists: true }
        }
        return utils.getPathInfo(actual, propertyName)
      }
      const { value, exists } = getValue()
      const pass
        = exists
          && (args.length === 1 || jestEquals(expected, value, customTesters))

View on GitHub (pinned to 1fa9837ec2)

Solutions

  1. Guard the value before asserting: only call `toHaveProperty` when the value is non-null.
  2. If absence is expected, use `toBe(null)` / `toBeUndefined()` instead of `toHaveProperty`.
  3. Fix the upstream producer so it returns an object (e.g. add a fallback `{}`) instead of null.
  4. For optional chains, assert on the nested value directly with `toBeUndefined()`.

Example fix

// before
expect(user.profile).toHaveProperty('email')

// after
expect(user.profile).not.toBeNull()
expect(user.profile).toHaveProperty('email')
Defensive patterns

Strategy: type-guard

Validate before calling

if (value == null) { throw new Error(`cannot assert properties on ${value}`) }
expect(value).toHaveProperty('foo')

Type guard

const isRecord = (v: unknown): v is Record<string, unknown> =>
  v !== null && typeof v === 'object'

Prevention

When it happens

Trigger: Calling `expect(null).toHaveProperty('foo')` or `expect(undefined).toHaveProperty('a.b')`, including when a lookup function or selector returned nothing and the result was passed straight into `expect()`.

Common situations: Querying a DOM element or config object that does not exist (returns null); reading an optional API field that was absent; destructuring from a possibly-absent response without a default; async value that resolved to undefined.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/23840cabb1432398. Report an issue: GitHub.