denoland/deno · error · TypeError
ERR_AMBIGUOUS_ARGUMENT
ERR_AMBIGUOUS_ARGUMENT
Error message
The "error/message" argument is ambiguous. The error message "${actual.message}" is identical to the message. What it means
When a string error spec is used with assert.throws/assert.rejects, expectsError compares it to the thrown error's message. If the two are identical, the call is ambiguous — the same text is both the expected message and (implicitly) the assertion's failure message — so the polyfill throws ERR_AMBIGUOUS_ARGUMENT instead of guessing. Older Node versions only warned (DEP0018-adjacent behavior); current Node and this polyfill throw.
Solutions
- Wrap the expectation in a RegExp: assert.throws(fn, /boom/).
- Or use a validation object: assert.throws(fn, { message: 'boom' }).
- If the string was meant as the assertion's failure message, move it to the third argument: assert.throws(fn, undefined, 'boom') — or simply assert.throws(fn) and let the thrown error speak for itself.
- When building expectations dynamically, derive them from a different source than the runtime message (a shared constant is fine, but change one side's form, e.g. new RegExp(escaped)).
Example fix
// before
assert.throws(() => { throw new Error('boom'); }, 'boom');
// after
assert.throws(() => { throw new Error('boom'); }, /boom/); Defensive patterns
Strategy: validation
Validate before calling
// Compare by pattern, never by identical literal string const expectMessage = (msg) => (msg instanceof RegExp ? msg : new RegExp(msg)); assert.throws(fn, expectMessage(thrownMessage));
Type guard
const isUnambiguousErrorSpec = (error, actualMsg) => !(typeof error === 'string' && error === actualMsg);
Try / catch
try {
assert.throws(fn, 'boom');
} catch (e) {
if (e.code === 'ERR_AMBIGUOUS_ARGUMENT') {
assert.throws(fn, /boom/); // re-express the expectation unambiguously
} else throw e;
} Prevention
- Avoid string expectations entirely; prefer RegExp or { message } objects.
- Never build the expected string from the same runtime value the code throws.
- When upgrading runtimes, grep tests for assert.throws(fn, '<literal>') patterns that duplicate thrown messages.
When it happens
Trigger: assert.throws(() => { throw new Error('boom') }, 'boom') — the thrown Error's .message is strictly equal to the string passed as the expectation.
Common situations: Tests written as assert.throws(fn, err.message) after capturing a message dynamically, making expected and actual text identical by construction; generated tests that build the expected string from the same constant the code under test throws; upgrading Node/Deno from versions that tolerated this with a deprecation warning, breaking previously green suites.
Related errors
- ERR_INVALID_ARG_VALUE
- ERR_ASSERTION
- ERR_CONSTRUCT_CALL_REQUIRED
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_RETURN_VALUE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/f169c2058c4e4319.
Report an issue: GitHub.
Appendix: source
Thrown at ext/node/polyfills/assert.ts:394
function expectsError(
stackStartFn,
actual,
error,
message,
) {
if (typeof error === "string") {
if (arguments.length === 4) {
throw new ERR_INVALID_ARG_TYPE("error", [
"Object",
"Error",
"Function",
"RegExp",
], error);
}
if (typeof actual === "object" && actual !== null) {
if (actual.message === error) {
throw new ERR_AMBIGUOUS_ARGUMENT(
"error/message",
`The error message "${actual.message}" is identical to the message.`,
);
}
} else if (actual === error) {
throw new ERR_AMBIGUOUS_ARGUMENT(
"error/message",
`The error "${actual}" is identical to the message.`,
);
}
message = error;
error = undefined;
} else if (
error != null &&
typeof error !== "object" &&
typeof error !== "function"
) {
throw new ERR_INVALID_ARG_TYPE("error", [View on GitHub (pinned to 9ad36f7a2c)