Skip to content

Comments

fix: replace original request body after middleware execution (#77662)#7

Open
MitchLewis930 wants to merge 1 commit intopr_037_beforefrom
pr_037_after
Open

fix: replace original request body after middleware execution (#77662)#7
MitchLewis930 wants to merge 1 commit intopr_037_beforefrom
pr_037_after

Conversation

@MitchLewis930
Copy link

@MitchLewis930 MitchLewis930 commented Jan 30, 2026

PR_037

Summary by CodeRabbit

  • New Features

    • Added Node.js middleware support as an experimental feature.
  • Bug Fixes

    • Improved request body handling in middleware to properly clone and finalize request streams, avoiding issues with non-clonable bodies.
  • Tests

    • Added comprehensive test coverage for server actions with Node.js middleware, including body size limit scenarios and rewrite functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

…#77662)

In vercel#77553 we fixed reading the
request body in middleware using the `nodejs` runtime. However, this
caused issues with subsequent reads like in server actions. In sandbox,
[we
run](https://github.com/vercel/next.js/blob/1e62ce2c61048ddc0297f1a4f268894541975521/packages/next/src/server/web/sandbox/sandbox.ts#L146-L148)
`.finalize()` after middleware is executed so we should do the same
here.

Fixes vercel#77646

---------

Co-authored-by: JJ Kasper <jj@jjsweb.site>
@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

Changes introduce node-based middleware support for tests by adding request body handling to the server middleware path, creating conditional test drivers for node middleware variants, and modifying middleware configuration to support nodejs runtime execution.

Changes

Cohort / File(s) Summary
Server Middleware Request Body Handling
packages/next/src/server/next-server.ts
Added request body detection for non-GET/HEAD methods, body cloning and forwarding logic, and try/finally block to finalize request body streams after adapter calls, improving body stream management in middleware.
Node Middleware Test Drivers
test/e2e/app-dir/actions/app-action-node-middleware.test.ts, app-action-form-state-node-middleware.test.ts, app-action-size-limit-invalid-node-middleware.test.ts
New test bootstrap files that set TEST_NODE_MIDDLEWARE environment variable to 'true' and require existing test suites, enabling reuse of tests under node middleware context.
Test Base File Enhancements
test/e2e/app-dir/actions/app-action.test.ts, app-action-form-state.test.ts, app-action-size-limit-invalid.test.ts
Enhanced nextTestSetup invocations with conditional overrideFiles option that maps middleware.js to middleware-node.js when TEST_NODE_MIDDLEWARE is set, supporting dynamic middleware substitution during test execution.
Middleware Configuration Files
test/e2e/app-dir/actions/middleware.js, middleware-node.js, next.config.js
Removed config matcher from middleware.js; added new middleware-node.js with nodejs runtime configuration and rewrite logic; enabled experimental.nodeMiddleware in next.config.js.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through middleware streams,
With request bodies flowing through dreams!
From node to test, the path now clears,
Try/finally blocks calm all fears—
Finalized bodies, no more tears! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal with only 'PR_037' provided, lacking required sections like what, why, how, or issue/PR links as specified in the template. Add detailed description following the template: explain what was fixed (request body handling), why it was needed (broken subsequent reads), and how it was solved (finalize after middleware). Include issue and PR links.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: addressing how the original request body is handled after middleware execution.
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 docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pr_037_after

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

Copy link

@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.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@test/e2e/app-dir/actions/app-action-size-limit-invalid-node-middleware.test.ts`:
- Around line 1-3: This file sets process.env.TEST_NODE_MIDDLEWARE at module
scope which can leak into other tests; capture the current value before
overwriting (e.g., const prev = process.env.TEST_NODE_MIDDLEWARE), set
process.env.TEST_NODE_MIDDLEWARE = 'true' as it currently does, and register an
afterAll cleanup that restores the original value
(process.env.TEST_NODE_MIDDLEWARE = prev or delete it if prev is undefined) so
the environment is not mutated for other tests; reference the module-level
assignment of process.env.TEST_NODE_MIDDLEWARE and add an afterAll hook to
restore the previous value.

In `@test/e2e/app-dir/actions/middleware-node.js`:
- Around line 13-18: Update the JSDoc for the exported config so the annotated
type matches the included runtime property: either remove the JSDoc annotation
entirely from the exported symbol config to let inference handle the shape, or
replace import('next/server').MiddlewareConfig with a more specific inline type
that includes runtime: 'nodejs' (and optional matcher if needed) so the runtime
property is allowed; ensure the modification targets the exported const named
config and the JSDoc comment referencing MiddlewareConfig.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1abba59 and bda5dc3.

📒 Files selected for processing (10)
  • packages/next/src/server/next-server.ts
  • test/e2e/app-dir/actions/app-action-form-state-node-middleware.test.ts
  • test/e2e/app-dir/actions/app-action-form-state.test.ts
  • test/e2e/app-dir/actions/app-action-node-middleware.test.ts
  • test/e2e/app-dir/actions/app-action-size-limit-invalid-node-middleware.test.ts
  • test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts
  • test/e2e/app-dir/actions/app-action.test.ts
  • test/e2e/app-dir/actions/middleware-node.js
  • test/e2e/app-dir/actions/middleware.js
  • test/e2e/app-dir/actions/next.config.js
💤 Files with no reviewable changes (1)
  • test/e2e/app-dir/actions/middleware.js
🧰 Additional context used
🧬 Code graph analysis (4)
test/e2e/app-dir/actions/app-action-form-state.test.ts (2)
test/lib/e2e-utils/index.ts (1)
  • FileRef (122-128)
turbopack/crates/turbo-tasks-fs/src/lib.rs (1)
  • join (1233-1244)
test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts (2)
test/lib/e2e-utils/index.ts (1)
  • FileRef (122-128)
turbopack/crates/turbo-tasks-fs/src/lib.rs (1)
  • join (1233-1244)
test/e2e/app-dir/actions/app-action.test.ts (2)
test/lib/e2e-utils/index.ts (1)
  • FileRef (122-128)
turbopack/crates/turbo-tasks-fs/src/lib.rs (1)
  • join (1233-1244)
packages/next/src/server/next-server.ts (2)
test/e2e/middleware-general/app/middleware-node.js (2)
  • params (18-30)
  • result (20-20)
test/e2e/middleware-general/app/middleware.js (2)
  • params (27-39)
  • result (29-29)
🔇 Additional comments (9)
test/e2e/app-dir/actions/next.config.js (1)

7-9: LGTM!

The experimental nodeMiddleware flag is correctly enabled to support the node-based middleware testing introduced in this PR.

test/e2e/app-dir/actions/middleware-node.js (1)

4-11: LGTM!

The middleware implementation is correct:

  • Uses async function as required
  • Properly rewrites requests matching the path pattern
  • Falls through with NextResponse.next() for other requests
test/e2e/app-dir/actions/app-action.test.ts (1)

2-2: LGTM!

The conditional middleware override is well-implemented:

  • FileRef is correctly used to reference the node middleware file
  • The overrideFiles pattern cleanly enables test reuse for both edge and node middleware scenarios
  • Path construction using join(__dirname, 'middleware-node.js') is correct

Also applies to: 21-27

test/e2e/app-dir/actions/app-action-node-middleware.test.ts (1)

1-3: LGTM!

Clean test driver pattern that enables running the full action test suite under the node middleware configuration by setting the environment variable before requiring the base test.

test/e2e/app-dir/actions/app-action-form-state.test.ts (1)

2-4: LGTM!

The middleware override pattern is consistently applied, matching the implementation in app-action.test.ts.

Also applies to: 7-13

test/e2e/app-dir/actions/app-action-form-state-node-middleware.test.ts (1)

1-3: LGTM!

Consistent test driver pattern for the form state tests under node middleware configuration.

test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts (2)

1-1: LGTM!

The middleware override setup is consistent with the other test files in this PR.

Also applies to: 6-6, 12-18


49-57: Good catch: patched configs include nodeMiddleware: true.

The patched next.config.js contents correctly include nodeMiddleware: true alongside the invalid serverActions.bodySizeLimit values. This ensures the node middleware feature remains enabled when the config is temporarily overwritten during these test cases.

Also applies to: 64-76, 83-95

packages/next/src/server/next-server.ts (1)

1689-1709: Good safeguard for node middleware body handling.

Cloning the body for the adapter and finalizing in finally should reliably restore the original stream for downstream reads, even on errors.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +1 to +3
process.env.TEST_NODE_MIDDLEWARE = 'true'

require('./app-action-size-limit-invalid.test')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Restore TEST_NODE_MIDDLEWARE after the suite to avoid env leakage.

Since this sets a global env var at module scope, it can bleed into subsequent test files in the same worker. Consider saving the previous value and restoring it in afterAll.

🔧 Suggested patch
-process.env.TEST_NODE_MIDDLEWARE = 'true'
-
-require('./app-action-size-limit-invalid.test')
+const previousValue = process.env.TEST_NODE_MIDDLEWARE
+process.env.TEST_NODE_MIDDLEWARE = 'true'
+
+require('./app-action-size-limit-invalid.test')
+
+afterAll(() => {
+  if (previousValue === undefined) {
+    delete process.env.TEST_NODE_MIDDLEWARE
+  } else {
+    process.env.TEST_NODE_MIDDLEWARE = previousValue
+  }
+})
🤖 Prompt for AI Agents
In
`@test/e2e/app-dir/actions/app-action-size-limit-invalid-node-middleware.test.ts`
around lines 1 - 3, This file sets process.env.TEST_NODE_MIDDLEWARE at module
scope which can leak into other tests; capture the current value before
overwriting (e.g., const prev = process.env.TEST_NODE_MIDDLEWARE), set
process.env.TEST_NODE_MIDDLEWARE = 'true' as it currently does, and register an
afterAll cleanup that restores the original value
(process.env.TEST_NODE_MIDDLEWARE = prev or delete it if prev is undefined) so
the environment is not mutated for other tests; reference the module-level
assignment of process.env.TEST_NODE_MIDDLEWARE and add an afterAll hook to
restore the previous value.

Comment on lines +13 to +18
/**
* @type {import('next/server').MiddlewareConfig}
*/
export const config = {
runtime: 'nodejs',
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's understand the repository structure and find Next.js type definitions
git ls-files | grep -E "(middleware|server)" | head -20

Repository: Signal65/next.js-CodeRabbit

Length of output: 1103


🏁 Script executed:

# Search for MiddlewareConfig type definition in the codebase
rg -n "type MiddlewareConfig|interface MiddlewareConfig" --type=ts -A 10

Repository: Signal65/next.js-CodeRabbit

Length of output: 4557


🏁 Script executed:

# Also search for middleware config exports to understand the type structure
rg -n "export.*MiddlewareConfig" --type=ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1073


🏁 Script executed:

# Check if runtime property is used in middleware configs anywhere
rg -n "runtime.*nodejs" --type=ts -C 3

Repository: Signal65/next.js-CodeRabbit

Length of output: 25948


🏁 Script executed:

# Let's check the MiddlewareConfigInputSchema to see all supported properties
sed -n '95,150p' packages/next/src/build/segment-config/middleware/middleware-config.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1417


🏁 Script executed:

# Let's check the actual file under review to see what it contains
cat -n test/e2e/app-dir/actions/middleware-node.js

Repository: Signal65/next.js-CodeRabbit

Length of output: 648


🏁 Script executed:

# Also check if there's a separate type definition for runtime in middleware context
rg -n "runtime.*nodejs" packages/next/src/build/segment-config/middleware/ -A 2 -B 2

Repository: Signal65/next.js-CodeRabbit

Length of output: 53


🏁 Script executed:

# Search for where runtime is parsed/validated in middleware config
rg -n "runtime" packages/next/src/build/segment-config/middleware/middleware-config.ts -A 2 -B 2

Repository: Signal65/next.js-CodeRabbit

Length of output: 53


🏁 Script executed:

# Check the types exported from next/server to understand what types are available
cat packages/next/src/server/web/types.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1931


🏁 Script executed:

# Let's look at what types are available in next/server.d.ts
cat packages/next/server.d.ts | head -30

Repository: Signal65/next.js-CodeRabbit

Length of output: 1286


🏁 Script executed:

# Search for all type definitions that include runtime in middleware context
rg -n "type.*Middleware.*Config|interface.*Middleware.*Config" packages/next/src --type=ts -A 5

Repository: Signal65/next.js-CodeRabbit

Length of output: 8896


Update JSDoc type annotation to include the runtime property or use a more specific type.

The MiddlewareConfig type exported from next/server does not include the runtime property, which is set to 'nodejs' in this config. Consider either:

  • Removing the JSDoc type annotation and relying on type inference
  • Using a more specific type that includes all properties: { runtime: 'nodejs'; matcher?: ... }
  • Or filing a feature request to add runtime to the official MiddlewareConfig type definition
Relevant code snippet
/**
 * `@type` {import('next/server').MiddlewareConfig}
 */
export const config = {
  runtime: 'nodejs',
}
🤖 Prompt for AI Agents
In `@test/e2e/app-dir/actions/middleware-node.js` around lines 13 - 18, Update the
JSDoc for the exported config so the annotated type matches the included runtime
property: either remove the JSDoc annotation entirely from the exported symbol
config to let inference handle the shape, or replace
import('next/server').MiddlewareConfig with a more specific inline type that
includes runtime: 'nodejs' (and optional matcher if needed) so the runtime
property is allowed; ensure the modification targets the exported const named
config and the JSDoc comment referencing MiddlewareConfig.

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.

2 participants