avajs/ava · error · AssertionError
The assertion message must be a string
Error message
The assertion message must be a string
What it means
AVA assertion messages must be a string or undefined. assertMessage (lib/assert.js:279) runs checkAssertionMessage on the message passed to any assertion and throws a generic Error (produced by fail(result)) when the message is neither undefined nor a string. This guards assertion output formatting: AVA cannot render non-string messages.
Source
Thrown at lib/assert.js:279
constructor({
pass = notImplemented,
pending = notImplemented,
fail = notImplemented,
failPending = notImplemented,
skip = notImplemented,
compareWithSnapshot = notImplemented,
experiments = {},
disableSnapshots = false,
} = {}) {
const withSkip = assertionFn => {
assertionFn.skip = skip;
return assertionFn;
};
const assertMessage = (message, assertion) => {
const result = checkAssertionMessage(message, assertion);
if (result !== true) {
throw fail(result);
}
};
this.pass = withSkip(() => pass());
this.fail = withSkip(message => {
assertMessage(message, 't.fail()');
throw fail(new AssertionError(message ?? 'Test failed via `t.fail()`', {
assertion: 't.fail()',
}));
});
this.is = withSkip((actual, expected, message) => {
assertMessage(message, 't.is()');
if (Object.is(actual, expected)) {
return pass();View on GitHub (pinned to bbfd946322)
Solutions
- Convert the value to a string before passing it: t.is(actual, expected, String(message)) or template literal `${message}`.
- Pass the Error's message property instead of the Error itself: t.fail(err.message).
- Omit the argument entirely (or pass undefined) if no message is needed; null must be removed since only undefined/string are accepted.
Example fix
// before
t.fail(new Error('boom'));
// after
t.fail('boom'); // or t.fail(error.message) Defensive patterns
Strategy: type-guard
Validate before calling
function isAssertionMessage(m) { return m === undefined || typeof m === 'string'; }
if (!isAssertionMessage(message)) throw new TypeError('Assertion message must be a string'); Type guard
const isAssertionMessage = (m) => m === undefined || typeof m === 'string';
Prevention
- Pass string literals or template literals as assertion messages.
- Never pass Error objects directly; use err.message.
- Use undefined (or omit) rather than null for 'no message'.
When it happens
Trigger: Calling any t.* assertion (t.fail(), t.is(), t.deepEqual(), t.true(), t.log-like assertions, etc.) with a message argument that is a number, boolean, object, Error, null, or other non-string, non-undefined value — e.g. t.is(got, want, 42) or t.fail(someError).
Common situations: Passing an Error object as the message out of habit from other frameworks, interpolating to a number, passing null explicitly (null is not undefined), or refactoring where a variable that is sometimes an object is used as the message.
Related errors
- message ?? 'Test failed via `t.fail()`'
- `t.like()` selector must be a non-empty object
- The `any` property of the second argument to `${assertion}`
- The second argument to `${assertion}` contains unexpected pr
- message
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/1ccc454e1fdf81ee.
Report an issue: GitHub.