denoland/deno · error · AssertionError

ERR_ASSERTION

ERR_ASSERTION

Error message

${actual} ${operator} ${expected}

What it means

innerFail is the terminal branch of node:assert when a comparison fails (ext/node/polyfills/assert.ts:130): if the caller supplied an Error object as the message, that error is rethrown as-is; otherwise it throws an AssertionError built from { actual, expected, message, operator, stackStartFn, diff }. The '${actual} ${operator} ${expected}' rendering is the AssertionError's generated message format, so this entry fires on every failed assertion that reaches innerFail (e.g. assert.throws mismatches routed through compareExceptionKey).

Source

Thrown at ext/node/polyfills/assert.ts:130

Assert.prototype.deepStrictEqual = deepStrictEqual;
Assert.prototype.notDeepStrictEqual = notDeepStrictEqual;
Assert.prototype.strictEqual = strictEqual;
Assert.prototype.notStrictEqual = notStrictEqual;
Assert.prototype.partialDeepStrictEqual = partialDeepStrictEqual;
Assert.prototype.throws = throws;
Assert.prototype.rejects = rejects;
Assert.prototype.doesNotThrow = doesNotThrow;
Assert.prototype.doesNotReject = doesNotReject;
Assert.prototype.ifError = ifError;
Assert.prototype.match = match;
Assert.prototype.doesNotMatch = doesNotMatch;

function innerFail(obj) {
  if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, obj.message)) {
    throw obj.message;
  }

  throw new AssertionError({
    actual: obj.actual,
    expected: obj.expected,
    message: obj.message,
    operator: obj.operator,
    stackStartFn: obj.stackStartFn,
    diff: obj.diff,
  });
}

function assert(...args) {
  innerOk(ok, args.length, ...new SafeArrayIterator(args));
}
const ok = assert;

class Comparison {
  constructor(obj, keys, actual) {
    for (const key of new SafeArrayIterator(keys)) {
      if (ReflectHas(obj, key)) {

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Inspect the AssertionError's actual/expected fields (or the diff) to see the divergence, then fix the code or the expectation
  2. In assert.throws validation objects, list only properties that must match (e.g. { name: 'TypeError', message: /boom/ }) instead of deep-equal whole errors
  3. Add assert.fail('why') with explicit messages at branch points so failures surface intent, not just values

Example fix

// before
assert.throws(() => parse('nope'), { message: 'exactly this' }); // message differs

// after
assert.throws(() => parse('nope'), { name: 'SyntaxError', message: /nope/ });
Defensive patterns

Strategy: try-catch

Try / catch

try { assert.strictEqual(actual, expected, 'context: why these must match'); } catch (e) { if (e.code === 'ERR_ASSERTION') { /* inspect e.actual/e.expected, fix code or expectation */ throw e; } throw e; }

Prevention

When it happens

Trigger: assert.strictEqual(1, 2); assert.throws(fn, { code: 'X' }) where fn threw no matching property; assert(fn, customMessageNotProvided); any failed ok/equals family assertion in strict mode routed via innerOk -> innerFail.

Common situations: Ordinary test failures — regressions where the value under test changed; overly loose expected objects in assert.throws that mismatch a property; NaN comparisons failing strict equality; async timing changing observed state between runs.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/ea4211b9a86d7a75. Report an issue: GitHub.