Skip to content

fix: ctx.assert() now throws errors that are instanceof HttpError#1937

Open
mibragimov wants to merge 2 commits intokoajs:masterfrom
mibragimov:fix/ctx-assert-instanceof
Open

fix: ctx.assert() now throws errors that are instanceof HttpError#1937
mibragimov wants to merge 2 commits intokoajs:masterfrom
mibragimov:fix/ctx-assert-instanceof

Conversation

@mibragimov
Copy link

Problem

ctx.assert() was delegated entirely to the http-assert package, which bundles its own copy of http-errors ~1.8.0. Because koa depends on http-errors ^2.0.0, npm installs two separate versions with distinct class prototypes. As a result, errors thrown by ctx.assert() fail an instanceof HttpError check even though the errors look identical:

import { HttpError } from 'koa'

router.get('/test', async (ctx) => {
  try {
    ctx.assert(false, 401, 'Unauthorized')
  } catch (e) {
    console.log(e instanceof HttpError) // ❌ false — should be true
  }
})

Fixes #1925

Solution

Replace the http-assert dependency with an inline assert() helper inside lib/context.js that creates HTTP errors through the same createError function (from http-errors ^2.0.0) used by ctx.throw() and re-exported as koa.HttpError.

The full http-assert API is preserved:

  • ctx.assert(value, status[, msg[, opts]])
  • ctx.assert.equal / notEqual / strictEqual / notStrictEqual
  • ctx.assert.deepEqual / notDeepEqual — now uses util.isDeepStrictEqual() (available since Node 9, koa requires Node ≥ 18)
  • ctx.assert.fail / ok

After this fix

console.log(e instanceof HttpError) // ✅ true

Tests

Added a new test case in __tests__/context/assert.test.js that asserts the thrown error is instanceof HttpError. All 430 existing tests continue to pass.

Fixes koajs#1925

ctx.assert() was delegated to http-assert, which bundles its own copy
of http-errors ~1.8.0. Because koa depends on http-errors ^2.0.0, npm
installs two separate versions, giving them distinct class prototypes.
As a result, errors thrown by ctx.assert() failed instanceof HttpError
even though they looked identical.

Replace the http-assert dependency with an inline assert() helper that
creates errors through the same createError (http-errors ^2.0.0)
instance used by ctx.throw() and re-exported as koa.HttpError.

The assert API is preserved:
  ctx.assert(value, status[, msg[, opts]])
  ctx.assert.equal / notEqual / strictEqual / notStrictEqual
  ctx.assert.deepEqual / notDeepEqual (now uses util.isDeepStrictEqual)
  ctx.assert.fail / ok
@codecov
Copy link

codecov bot commented Mar 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.90%. Comparing base (d3ea8bf) to head (ec34662).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1937   +/-   ##
=======================================
  Coverage   99.90%   99.90%           
=======================================
  Files           9        9           
  Lines        2094     2141   +47     
=======================================
+ Hits         2092     2139   +47     
  Misses          2        2           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Also fix assert() to handle undefined msg/opts correctly so all named
methods (assert.equal, assert.ok, assert.strictEqual, etc.) produce
errors with the correct status code.
@mibragimov mibragimov marked this pull request as ready for review March 7, 2026 03:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[fix] ctx.assert() throws specific error classes

1 participant