denoland/deno · error · TypeError
ERR_INVALID_ARG_VALUE
ERR_INVALID_ARG_VALUE
Error message
The argument 'error' may not be an empty object. Received ${expected} What it means
In assert.throws/assert.rejects, when the expected argument is a plain object it acts as a property validator: its own keys are checked against the thrown error, so an object with zero keys validates nothing and is rejected up front (ext/node/polyfills/assert.ts:246) with ERR_INVALID_ARG_VALUE 'error may not be an empty object'. Note that Error instances are exempt (name/message are implicitly added), but {}, Object.create(null), or objects whose own enumerable keys are absent throw.
Source
Thrown at ext/node/polyfills/assert.ts:246
const err = new AssertionError({
actual,
expected,
message,
operator: "deepStrictEqual",
stackStartFn: fn,
diff: this?.[kOptions]?.diff,
});
err.operator = fn.name;
throw err;
} else {
// Handle validation objects.
const keys = ObjectKeys(expected);
// Special handle errors to make sure the name and the message are
// compared as well.
if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, expected)) {
ArrayPrototypePush(keys, "name", "message");
} else if (keys.length === 0) {
throw new ERR_INVALID_ARG_VALUE(
"error",
expected,
"may not be an empty object",
);
}
for (const key of new SafeArrayIterator(keys)) {
if (
typeof actual[key] === "string" &&
isRegExp(expected[key]) &&
RegExpPrototypeExec(expected[key], actual[key]) !== null
) {
continue;
}
compareExceptionKey(actual, expected, key, message, keys, fn);
}
return;
}
// Guard instanceof against arrow functions as they don't have a prototype.View on GitHub (pinned to 89f33cbef2)
Solutions
- Drop the second argument entirely to assert 'throws with anything': assert.throws(fn)
- Specify at least one property to validate: assert.throws(fn, { name: 'TypeError' })
- When building expected dynamically, fall back to a bare call when the matcher object would be empty: Object.keys(matcher).length ? assert.throws(fn, matcher) : assert.throws(fn)
Example fix
// before
assert.throws(() => JSON.parse('{'), {});
// after
assert.throws(() => JSON.parse('{'), { name: 'SyntaxError' }); Defensive patterns
Strategy: validation
Validate before calling
if (matcher && typeof matcher === 'object' && !Object.keys(matcher).length) matcher = undefined; // assert 'throws with anything'
Type guard
function isNonEmptyErrorMatcher(v) { return v == null || typeof v === 'function' || Object.keys(v).length > 0 || v instanceof Error; } Try / catch
try { assert.throws(fn, matcher); } catch (e) { if (e.code === 'ERR_INVALID_ARG_VALUE' && /empty object/.test(e.message)) assert.throws(fn); else throw e; } Prevention
- Never use {} as the expected argument; omit it to assert any throw
- When building matchers dynamically, assert at least one key before use
When it happens
Trigger: assert.throws(fn, {}); assert.rejects(promise, {}); dynamic expected objects built from optional fields where every field was undefined or non-enumerable, leaving zero keys.
Common situations: Placeholder tests written as assert.throws(fn, {}) meaning 'any throw'; config-driven assertion builders merging optional matchers that end up empty; objects whose properties are defined only on the prototype (ObjectKeys sees none).
Related errors
- ERR_INVALID_ARG_TYPE
- ERR_CONSTRUCT_CALL_REQUIRED
- ERR_ASSERTION
- ERR_INVALID_RETURN_VALUE
- ERR_AMBIGUOUS_ARGUMENT
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/f761b1aadf1a76f0.
Report an issue: GitHub.