Skip to content

fix: throw Koa HttpError from ctx.assert instead of nested http-errors instance - #1992

Open
marceli1404 wants to merge 2 commits into
koajs:masterfrom
marceli1404:fix/ctx-assert-httperror
Open

fix: throw Koa HttpError from ctx.assert instead of nested http-errors instance#1992
marceli1404 wants to merge 2 commits into
koajs:masterfrom
marceli1404:fix/ctx-assert-httperror

Conversation

@marceli1404

@marceli1404 marceli1404 commented Jul 30, 2026

Copy link
Copy Markdown

Fixes #1925

\ctx.assert\ delegates to \http-assert, which depends on \http-errors@~1.8.0\ (installed in its own
ode_modules). Since Koa exports \HttpError\ from its own \http-errors@^2.0.0\ dependency, errors thrown by \ctx.assert()\ did not satisfy \�rr instanceof Koa.HttpError.

This change wraps \http-assert\ to re-throw assertion failures using Koa's \createError\ (from \http-errors\ v2), so both \ctx.assert\ and all its helper methods (.ok, .equal, .strictEqual, etc.) throw proper \HttpError\ instances.

Test plan:


  • ode --test\ — 446 tests, 0 failures

  • pm run build\ — passes

  • pm run lint\ — passes

Summary by Sourcery

Ensure ctx.assert and its helper methods throw Koa.HttpError instances instead of errors from the nested http-assert/http-errors dependency.

Bug Fixes:

  • Fix HttpError instanceof checks by rethrowing assertion failures using Koa's http-errors integration.

Enhancements:

  • Wrap http-assert to normalize assertion errors into Koa HttpError, preserving relevant error properties.

Tests:

  • Extend context assert tests to verify HttpError instances and behavior of all assert helper methods.

Summary by CodeRabbit

  • Bug Fixes

    • Improved context assertion errors so they consistently use standard HTTP error types.
    • Preserved assertion status, messages, exposure settings, and custom error details.
    • Ensured all built-in assertion helpers follow the same error-handling behavior.
  • Tests

    • Expanded coverage for successful assertions and expected error properties across all assertion helpers.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a7dc3d50-b661-4656-9278-f5f73108dc39

📥 Commits

Reviewing files that changed from the base of the PR and between 3d01a32 and a5b56f1.

📒 Files selected for processing (1)
  • __tests__/context/assert.test.js

📝 Walkthrough

Walkthrough

ctx.assert and its helper methods now convert assertion failures with numeric status values into http-errors instances while retaining permitted custom properties. The context prototype uses the wrapped assertion implementation. Tests cover successful assertions and failures from assert, ok, equal, strictEqual, notEqual, and fail, including status, message, exposure, and Koa.HttpError checks.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the change to make ctx.assert throw Koa HttpError instead of a nested http-errors instance.
Linked Issues check ✅ Passed The implementation and tests address issue #1925 by making ctx.assert and its helpers throw errors recognized as Koa HttpError instances.
Out of Scope Changes check ✅ Passed The implementation and tests remain within the linked issue scope of correcting ctx.assert error types and preserving error properties.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Wraps ctx.assert and its helper methods to rethrow assertion failures as Koa.HttpError instances using Koa’s http-errors v2 createError, and extends tests to enforce instanceof Koa.HttpError and behavior of all assertion helpers.

Sequence diagram for ctx.assert rethrowing Koa.HttpError

sequenceDiagram
  participant Context
  participant assert_wrapper as assert
  participant httpAssert
  participant createError

  Context->>assert_wrapper: assert(condition, status, message, props)
  assert_wrapper->>httpAssert: httpAssert(condition, status, message, props)
  httpAssert-->>assert_wrapper: throw err with status
  assert_wrapper->>assert_wrapper: [err.status is number]
  assert_wrapper->>createError: createError(err.status, err.message, props)
  createError-->>Context: HttpError instance
  Context-->>Context: err instanceof HttpError
Loading

File-Level Changes

Change Details Files
Wrap ctx.assert so assertion failures are converted to Koa.HttpError instances instead of raw http-assert/http-errors v1 errors.
  • Introduce rethrowAssertionError helper that calls http-assert functions and, on failure, reconstructs and throws a new error via createError from Koa’s http-errors dependency.
  • Copy non-core enumerable properties from the original assertion error onto the new HttpError while omitting status, statusCode, message, expose, name, and stack.
  • Replace the context prototype’s assert reference from httpAssert to the wrapped assert function so ctx.assert uses the new behavior.
lib/context.js
Ensure all ctx.assert helper methods (.ok, .equal, .strictEqual, .notEqual, .fail) also throw Koa.HttpError instances and verify this via tests.
  • Wrap each function property on httpAssert with rethrowAssertionError and attach them to the exported assert object so helper methods inherit the new rethrow behavior.
  • Extend the ctx.assert test suite to require that thrown errors are instances of Koa.HttpError and to cover truthy assertions and each helper method’s error shape (status, message, expose).
  • Import Koa in the tests to access Koa.HttpError for instanceof checks and update existing test names and expectations accordingly.
lib/context.js
__tests__/context/assert.test.js

Assessment against linked issues

Issue Objective Addressed Explanation
#1925 Ensure that ctx.assert() throws instances of Koa's exported HttpError class so instanceof HttpError checks succeed.
#1925 Ensure that ctx.assert helper methods (ok, equal, strictEqual, notEqual, fail, etc.) also throw Koa HttpError instances consistent with ctx.assert().

Possibly linked issues

  • #[fix] ctx.assert() throws specific error classes: PR wraps http-assert so ctx.assert and helpers rethrow Koa’s HttpError, fixing instanceof checks described in issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.59259% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.81%. Comparing base (52d5e8f) to head (a5b56f1).

Files with missing lines Patch % Lines
lib/context.js 92.59% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1992      +/-   ##
==========================================
- Coverage   99.90%   99.81%   -0.10%     
==========================================
  Files           9        9              
  Lines        2109     2135      +26     
==========================================
+ Hits         2107     2131      +24     
- Misses          2        4       +2     

☔ View full report in Codecov by Harness.
📢 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.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The rethrowAssertionError wrapper creates new HttpError instances and discards the original stack; consider propagating err.stack or using the cause option so debugging still points to the original assertion location.
  • When copying properties from the original assertion error, you skip some standard fields but also any custom non-enumerable properties; if you rely on metadata from http-assert/http-errors, double-check whether additional fields (e.g. type or code) should be explicitly preserved.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `rethrowAssertionError` wrapper creates new `HttpError` instances and discards the original stack; consider propagating `err.stack` or using the `cause` option so debugging still points to the original assertion location.
- When copying properties from the original assertion error, you skip some standard fields but also any custom non-enumerable properties; if you rely on metadata from http-assert/http-errors, double-check whether additional fields (e.g. `type` or `code`) should be explicitly preserved.

## Individual Comments

### Comment 1
<location path="lib/context.js" line_range="15-17" />
<code_context>
 const Cookies = require('cookies')

+function rethrowAssertionError (fn) {
+  return function wrapped (...args) {
+    try {
+      fn(...args)
+    } catch (err) {
+      if (err.status && typeof err.status === 'number') {
</code_context>
<issue_to_address>
**issue (bug_risk):** Wrapped assert functions don't preserve the original `this` or return value.

The wrapper invokes `fn(...args)` without preserving `this` or returning the result, which can change behavior for `httpAssert` functions that rely on context or return values. Please call `fn.apply(this, args)` and return its result so the wrapper preserves the original semantics while still translating errors.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread lib/context.js
Comment on lines +15 to +17
return function wrapped (...args) {
try {
fn(...args)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Wrapped assert functions don't preserve the original this or return value.

The wrapper invokes fn(...args) without preserving this or returning the result, which can change behavior for httpAssert functions that rely on context or return values. Please call fn.apply(this, args) and return its result so the wrapper preserves the original semantics while still translating errors.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
__tests__/context/assert.test.js (1)

18-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover custom-property preservation.

The wrapper explicitly transfers permitted properties, but no test verifies that contract. Add a failing assertion with a custom property and assert it survives reconstruction.

Proposed test
+  it('should retain custom assertion properties', () => {
+    const ctx = context()
+
+    assert.throws(
+      () => ctx.assert(false, 418, 'teapot', { requestId: 'test-request' }),
+      err => {
+        assert.ok(err instanceof Koa.HttpError)
+        assert.strictEqual(err.requestId, 'test-request')
+        return true
+      }
+    )
+  })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@__tests__/context/assert.test.js` around lines 18 - 97, Add coverage to the
relevant HttpError reconstruction test around the existing ctx.assert cases by
assigning a permitted custom property to the thrown error and asserting that
property remains after reconstruction. Ensure the test verifies custom-property
preservation alongside the existing status, message, and expose assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@__tests__/context/assert.test.js`:
- Around line 18-97: Add coverage to the relevant HttpError reconstruction test
around the existing ctx.assert cases by assigning a permitted custom property to
the thrown error and asserting that property remains after reconstruction.
Ensure the test verifies custom-property preservation alongside the existing
status, message, and expose assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ae34afaa-c153-4817-a3a8-94de2c96aa3f

📥 Commits

Reviewing files that changed from the base of the PR and between 52d5e8f and 3d01a32.

📒 Files selected for processing (2)
  • __tests__/context/assert.test.js
  • lib/context.js

@marceli1404

Copy link
Copy Markdown
Author

@fengmk2 @dead-horse — friendly ping. This PR fixes #1925: ctx.assert() now throws proper Koa.HttpError instances (matching the documented behavior and the JSDoc in lib/context.js), instead of errors from the nested http-assert copy of http-errors. Added a regression test covering custom error properties. All 447 tests pass. Thanks for considering!

@fengmk2

fengmk2 commented Aug 4, 2026

Copy link
Copy Markdown
Member

@marceli1404 I think we should change the document description is better than change the code.

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

2 participants