jestjs/jest · error · TypeError

expected value must be a string if received value is a strin

Error message

expected value must be a string if received value is a string

What it means

Thrown by `toContain` (matchers.ts:484-502) specifically when the received value is a string but the expected argument is not. Because `String.prototype.indexOf` only accepts string search values, Jest enforces symmetry: a string received demands a string expected, otherwise it throws a `TypeError` rather than silently returning -1. The error includes both `printWithType` for Expected and Received.

Source

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

    if (received == null) {
      throw new Error(
        matcherErrorMessage(
          matcherHint(matcherName, undefined, undefined, options),
          `${RECEIVED_COLOR('received')} value must not be null nor undefined`,
          printWithType('Received', received, printReceived),
        ),
      );
    }

    if (typeof received === 'string') {
      const wrongTypeErrorMessage = `${EXPECTED_COLOR(
        'expected',
      )} value must be a string if ${RECEIVED_COLOR(
        'received',
      )} value is a string`;

      if (typeof expected !== 'string') {
        throw new TypeError(
          matcherErrorMessage(
            matcherHint(matcherName, received, String(expected), options),
            wrongTypeErrorMessage,
            // eslint-disable-next-line prefer-template
            printWithType('Expected', expected, printExpected) +
              '\n' +
              printWithType('Received', received, printReceived),
          ),
        );
      }

      const index = received.indexOf(String(expected));
      const pass = index !== -1;

      const message = () => {
        const labelExpected = `Expected ${
          typeof expected === 'string' ? 'substring' : 'value'
        }`;

View on GitHub (pinned to f49721c78e)

Solutions

  1. If matching a pattern, switch to `toMatch(/foo/)` or `toMatch('foo')`.
  2. Coerce the expected value to a string: `.toContain(String(id))`.
  3. If you meant to check array membership, make sure the received value is an array, not a string.
  4. Log `typeof expected` to confirm it is not undefined/object before the assertion.

Example fix

// before
expect(message).toContain(/error/i); // wrong matcher / wrong type

// after
expect(message).toMatch(/error/i);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof received === 'string' && typeof expected !== 'string') {
  throw new Error(`received is a string; expected must also be a string, got ${typeof expected}`);
}
expect(received).toContain(expected);

Type guard

const isValidContainArgs = (received: unknown, expected: unknown): boolean =>
  typeof received !== 'string' || typeof expected === 'string';

Try / catch

try {
  expect(received).toContain(expected);
} catch (e) {
  if (e instanceof TypeError && /must be a string if/.test(e.message)) {
    // switch to toMatch for regex, or coerce expected to String
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `expect('hello world').toContain(5)` (number), `expect(text).toContain(/foo/)` (regex — use `toMatch` instead), `expect(html).toContain({tag: 'div'})` (object), or `expect(str).toContain(undefined)` when an optional value was not supplied.

Common situations: Confusing `toContain` with `toMatch` (regex matching); passing a parsed token whose type was assumed; substring checks where the search term came from numeric IDs; refactor that changed an argument type from string to number.

Related errors


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