Skip to content

fix: sync set.status with actual response status in onAfterResponse#1820

Open
eL1fe wants to merge 2 commits intoelysiajs:mainfrom
eL1fe:fix/set-status-in-after-response
Open

fix: sync set.status with actual response status in onAfterResponse#1820
eL1fe wants to merge 2 commits intoelysiajs:mainfrom
eL1fe:fix/set-status-in-after-response

Conversation

@eL1fe
Copy link
Copy Markdown

@eL1fe eL1fe commented Mar 25, 2026

Summary

set.status in onAfterResponse always showed 200 even when the actual response had a different status code. This broke logging/monitoring middleware.

Problem

new Elysia()
  .onAfterResponse(({ set }) => {
    console.log(set.status) // always 200, even for 401/404/etc
  })
  .get('/test', () => new Response('unauthorized', { status: 401 }))

The handler returns a 401 Response, the client gets 401, but set.status in onAfterResponse was never updated from the response.

Changes

  • src/compose.ts: in the afterResponse codegen, sync c.set.status from c.responseValue.status when it's a Response object (route handler + 404 handler paths)
  • src/dynamic-handle.ts: in the finally block, sync set.status from context.response before running afterResponse hooks

Test plan

  • Handler returning Response with non-200 status → set.status reflects actual status
  • Handler using status() helper → still works correctly
  • Both AOT and dynamic modes tested
  • Full test suite passes (1525 pass, 0 fail)

Fixes #1445

Summary by CodeRabbit

  • Bug Fixes
    • Ensure HTTP status codes from native responses and custom-status responses are propagated consistently across request and cleanup flows.
    • Synchronize response status before running post-response hooks so final status is always reflected in downstream handling.

When a handler returns a Response object with a non-200 status,
set.status in onAfterResponse still showed 200. This broke logging
and monitoring middleware that relies on set.status.

Now set.status is updated from the response before afterResponse
hooks run — for both Response objects and ElysiaCustomStatusResponse.

Fixes elysiajs#1445
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2d4fd9db-0973-4b1a-9a10-7ee0f011234a

📥 Commits

Reviewing files that changed from the base of the PR and between 6a6c7b5 and 6b63a83.

📒 Files selected for processing (1)
  • src/dynamic-handle.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/dynamic-handle.ts

Walkthrough

Propagates HTTP status from returned Response or ElysiaCustomStatusResponse into ctx.set.status during cleanup/after-response handling so lifecycle hooks observe the actual response status.

Changes

Cohort / File(s) Summary
Compose handlers
src/compose.ts
After-response/cleanup logic now sets c.set.status from responseValue.status when responseValue is a native Response (in addition to existing ElysiaCustomStatusResponse handling). Review after-response mapping and error/cleanup branches.
Dynamic handler finalization
src/dynamic-handle.ts
finally block now synchronizes set.status from context.response.status when context.response is a native Response (or .code for ElysiaCustomStatusResponse) before running afterResponse hooks. Check ordering around late-assigned responses and afterResponse execution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through code at break of day,

Responses whispered what they'd say.
No longer stuck at two-hundred flat,
Statuses travel — imagine that!
A tiny hop, a tidy fix, hooray!

🚥 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 directly and accurately summarizes the main changes: synchronizing set.status with actual response status in onAfterResponse hooks.
Linked Issues check ✅ Passed The PR directly addresses issue #1445 by implementing status synchronization for both Response and ElysiaCustomStatusResponse objects in both AOT and dynamic modes.
Out of Scope Changes check ✅ Passed All changes in src/compose.ts and src/dynamic-handle.ts are directly scoped to fixing the set.status synchronization issue described in #1445.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/dynamic-handle.ts (1)

854-858: Consider reordering checks for consistency with compose.ts.

The fix correctly syncs set.status before afterResponse hooks. However, the order of instanceof checks differs from compose.ts, which checks ElysiaCustomStatusResponse first, then Response. While this doesn't affect correctness (since ElysiaCustomStatusResponse doesn't extend Response), aligning the order improves maintainability.

♻️ Suggested reorder for consistency
-			if (context.response instanceof Response)
-				set.status = context.response.status
-			else if (context.response instanceof ElysiaCustomStatusResponse)
+			if (context.response instanceof ElysiaCustomStatusResponse)
 				set.status = (context.response as any).code
+			else if (context.response instanceof Response)
+				set.status = context.response.status
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/dynamic-handle.ts` around lines 854 - 858, The status-assignment branch
in dynamic-handle.ts should check for ElysiaCustomStatusResponse before Response
to match compose.ts and improve consistency: in the block where you set
set.status from context.response (referencing context.response,
ElysiaCustomStatusResponse, Response, and set.status), reorder the instanceof
checks so you first test for ElysiaCustomStatusResponse and assign its .code,
then fall back to Response and assign .status.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/dynamic-handle.ts`:
- Around line 854-858: The status-assignment branch in dynamic-handle.ts should
check for ElysiaCustomStatusResponse before Response to match compose.ts and
improve consistency: in the block where you set set.status from context.response
(referencing context.response, ElysiaCustomStatusResponse, Response, and
set.status), reorder the instanceof checks so you first test for
ElysiaCustomStatusResponse and assign its .code, then fall back to Response and
assign .status.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 040e63e3-5347-4349-af58-29e4414e4181

📥 Commits

Reviewing files that changed from the base of the PR and between 56310be and 6a6c7b5.

📒 Files selected for processing (2)
  • src/compose.ts
  • src/dynamic-handle.ts

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.

Incorrect HTTP status during onRequest/onAfterResponse

1 participant