jestjs/jest · error · TypeError
${EXPECTED_COLOR('expected')} value must be a string if ${RE
Error message
${EXPECTED_COLOR('expected')} value must be a string if ${RECEIVED_COLOR('received')} value is a string What it means
Thrown by `toContain` (matchers.ts:491) when the received value is a string but the expected value is not a string. Because string containment uses `String.indexOf`, the expected argument must also be a string; the matcher refuses to silently coerce a non-string (which would hide a real bug).
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 8e6d128e4a)
Solutions
- Pass a string substring: toContain('world'), not toContain(5) or toContain(/world/).
- If you need a regex match, use toMatch instead of toContain.
- If testing array membership (non-string received), ensure the received value is actually an array.
- Coerce the expected to a string with String(...) only if that is genuinely intended.
Example fix
// before
expect('hello world').toContain(/world/);
expect('items: 5').toContain(5);
// after
expect('hello world').toContain('world');
// regex belongs in toMatch
expect('hello world').toMatch(/world/);
// coerce only if intended
expect('items: 5').toContain(String(5)); Defensive patterns
Strategy: type-guard
Validate before calling
const needle = searchValue;
if (typeof received === 'string' && typeof needle !== 'string') {
throw new Error('when received is a string, expected must also be a string');
}
expect(received).toContain(needle); Type guard
const isStringNeedle = (received: unknown, expected: unknown): expected is string => typeof received === 'string' ? typeof expected === 'string' : true;
Prevention
- Use toMatch for regex and toContain for substring; keep them distinct.
- When received is a string, always pass a string substring.
- Add TS types so the expected type aligns with received.
When it happens
Trigger: Calling `expect('hello world').toContain(5)` (number), `toContain(/world/)` (regex), or `toContain({a:1})` (object). The received is a string, so indexOf semantics require a string expected.
Common situations: Developer intends substring search but passes a number/object; confusing toContain (substring) with toMatch (regex); passing a value from a typed source that is not a string; copy-paste from an array test where toContain takes any value.
Related errors
- ${RECEIVED_COLOR('received')} value must not be null nor und
- ${RECEIVED_COLOR('received')} value must be a string
- ${EXPECTED_COLOR('expected')} value must be a number
- ${RECEIVED_COLOR('received')} value must be a number
- ${EXPECTED_COLOR('expected')} value must be a function
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/3dc39d13611a45f8.
Report an issue: GitHub.