Description
There is a critical issue in H3ravel where HTTP request and response state persist across multiple requests, leading to incorrect behaviour until the dev server is restarted.
Example Scenario
- User submits a form with validation.
- Validation fails → user is redirected back (expected).
- User corrects the form and submits again.
- Unexpected behaviour: user is still redirected back indefinitely.
Other observed effects:
- If the first request returns a
200 or 201, all subsequent responses return the same status.
- If the first request hits a
404, all subsequent requests (even to valid routes) return 404.
- This persists until the dev server is restarted.
Impact
- Makes form validation unusable
- Breaks routing correctness
- Completely invalidates HTTP lifecycle guarantees
- Forces server restarts during development
This is a blocking bug for real-world usage.
Root Cause (Suspected)
The issue appears to stem from request, response, and context reuse across requests, specifically:
-
HttpContext is cached on the H3Event and reused:
if (!fresh && (event as any)._h3ravelContext)
return (event as any)._h3ravelContext
-
this.h3Event, this.context, and container bindings (http.request, http.response) are overwritten and reused globally.
-
The response object (or its prepared state) leaks into subsequent requests.
-
Kernel termination does not reset or fully isolate per-request state.
This violates the expectation that every HTTP request must have a fresh request, response, and context lifecycle.
Relevant Code
framework/core/Application.ts
this.h3App?.all('/**', async (event) => {
this.context = (event) => this.buildContext(event, config)
this.h3Event = event
const context = await this.context!(event)
const kernel = this.make(IKernel)
this.bind('http.context', () => context)
this.bind('http.request', () => context.request)
this.bind('http.response', () => context.response)
const response = await kernel.handle(context.request)
if (response) this.bind('http.response', () => response)
kernel.terminate(context.request, response!)
})
if (!fresh && (event as any)._h3ravelContext)
return (event as any)._h3ravelContext
Expected Behavior
-
Every HTTP request must:
- Receive a fresh Request instance
- Receive a fresh Response instance
- Have an isolated
HttpContext
-
Response status, headers, and body must never leak into subsequent requests.
-
Validation failures must not affect future requests once corrected.
Tasks
Acceptance Criteria
Difficulty
🔴 High (Core lifecycle bug)
Description
There is a critical issue in H3ravel where HTTP request and response state persist across multiple requests, leading to incorrect behaviour until the dev server is restarted.
Example Scenario
Other observed effects:
200or201, all subsequent responses return the same status.404, all subsequent requests (even to valid routes) return404.Impact
This is a blocking bug for real-world usage.
Root Cause (Suspected)
The issue appears to stem from request, response, and context reuse across requests, specifically:
HttpContextis cached on theH3Eventand reused:this.h3Event,this.context, and container bindings (http.request,http.response) are overwritten and reused globally.The response object (or its prepared state) leaks into subsequent requests.
Kernel termination does not reset or fully isolate per-request state.
This violates the expectation that every HTTP request must have a fresh request, response, and context lifecycle.
Relevant Code
framework/core/Application.ts
Expected Behavior
Every HTTP request must:
HttpContextResponse status, headers, and body must never leak into subsequent requests.
Validation failures must not affect future requests once corrected.
Tasks
Identify all points where request, response, or context is cached or reused.
Ensure a new Response instance is created per request.
Ensure container bindings for
http.requestandhttp.responseare request-scoped, not global.Prevent
_h3ravelContextfrom persisting across unrelated requests.Review kernel lifecycle and termination cleanup.
Add regression tests covering:
Acceptance Criteria
Difficulty
🔴 High (Core lifecycle bug)