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
- Guard the value before asserting: only call `toHaveProperty` when the value is non-null.
- If absence is expected, use `toBe(null)` / `toBeUndefined()` instead of `toHaveProperty`.
- Fix the upstream producer so it returns an object (e.g. add a fallback `{}`) instead of null.
- 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
- Always confirm the value is non-null before calling toHaveProperty.
- Use optional chaining in the producer so undefined never reaches expect.
- Prefer asserting absence explicitly with toBeUndefined when null is valid.
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
- expected function to throw an error, but it didn't
- ${utils.inspect(assertion._obj)} is not a spy or a call to a
- ${utils.inspect(resultSpy)} is not a spy or a call to a spy
- expect.poll() is not supported in combination with .resolves
- You must provide a Promise to expect() when using .resolves,
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/23840cabb1432398.
Report an issue: GitHub.