jestjs/jest · error · Error

expected value must be a non-null object

Error message

expected value must be a non-null object

What it means

Thrown by `toMatchObject` (matchers.ts:894) when the expected argument (the subset template) is not a non-null object. `toMatchObject` walks the expected object's keys to verify they exist as a subset of received; a primitive/null/undefined expected cannot be iterated. The check is `typeof expected !== 'object' || expected === null`.

Source

Thrown at packages/expect/src/matchers.ts:912

  toMatchObject(received: object, expected: object) {
    const matcherName = 'toMatchObject';
    const options: MatcherHintOptions = {
      isNot: this.isNot,
      promise: this.promise,
    };

    if (typeof received !== 'object' || received === null) {
      throw new Error(
        matcherErrorMessage(
          matcherHint(matcherName, undefined, undefined, options),
          `${RECEIVED_COLOR('received')} value must be a non-null object`,
          printWithType('Received', received, printReceived),
        ),
      );
    }

    if (typeof expected !== 'object' || expected === null) {
      throw new Error(
        matcherErrorMessage(
          matcherHint(matcherName, undefined, undefined, options),
          `${EXPECTED_COLOR('expected')} value must be a non-null object`,
          printWithType('Expected', expected, printExpected),
        ),
      );
    }

    const pass = equals(received, expected, [
      ...this.customTesters,
      iterableEquality,
      subsetEquality,
    ]);

    const message = pass
      ? () =>
          // eslint-disable-next-line prefer-template
          matcherHint(matcherName, undefined, undefined, options) +

View on GitHub (pinned to f49721c78e)

Solutions

  1. Pass a plain object describing the expected subset: `.toMatchObject({status: 'ok'})`.
  2. If the expected is dynamic, validate it is a non-null object before the test.
  3. Log `typeof expected` and confirm it is `'object'` and not `null`.
  4. Use `toEqual` for full equality or `toContainEqual` for membership if a subset doesn't fit.

Example fix

// before
expect(user).toMatchObject(user.status); // user.status is a string

// after
expect(user).toMatchObject({status: user.status});
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof expected !== 'object' || expected === null) {
  throw new Error(`expected must be a non-null object, got ${expected === null ? 'null' : typeof expected}`);
}
expect(received).toMatchObject(expected);

Type guard

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

Try / catch

try {
  expect(received).toMatchObject(expected);
} catch (e) {
  if (e instanceof Error && /expected value must be a non-null object/.test(e.message)) {
    console.error('expected was', typeof expected, expected);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `expect(obj).toMatchObject('foo')` (string), `.toMatchObject(123)` (number), `.toMatchObject(null)`, `.toMatchObject(undefined)` (when an optional value was not supplied), or `.toMatchObject([1,2,3])` (array — technically allowed by the check but unusual; arrays pass since `typeof [] === 'object'`).

Common situations: Passing a primitive constant where a shape object was intended; refactor that replaced an object literal with a single value; importing a fixture that resolved to undefined; passing a class instance where a plain object was expected (instance is fine — it's an object).

Related errors


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