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
- If matching a pattern, switch to `toMatch(/foo/)` or `toMatch('foo')`.
- Coerce the expected value to a string: `.toContain(String(id))`.
- If you meant to check array membership, make sure the received value is an array, not a string.
- 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
- Use `toMatch` for regex matching, not `toContain`.
- Coerce numeric search terms with `String(...)` when searching strings.
- Keep received/expected types symmetric in helper functions.
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
- received value must be a string
- expected value must be a string or regular expression
- expected path must be a string or array
- expected value must be a number
- received value must be a number
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/ec3637454917c633.json.
Report an issue: GitHub.