Skip to content

fix(routing): serialize route-scoped middleware as plain handlers - #4558

Open
ShreeBohara wants to merge 1 commit into
nitrojs:mainfrom
ShreeBohara:fix/routed-middleware-serialization
Open

fix(routing): serialize route-scoped middleware as plain handlers#4558
ShreeBohara wants to merge 1 commit into
nitrojs:mainfrom
ShreeBohara:fix/routed-middleware-serialization

Conversation

@ShreeBohara

Copy link
Copy Markdown
Contributor

🔗 Linked issue

Resolves #4557

❓ Type of change

  • 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

Route-scoped middleware (a handlers entry with middleware: true and a route pattern) returns a
500 with TypeError: fn is not a function for every matching request. Details and a minimal
reproduction are in #4557.

findRoutedMiddleware serialized each match with serializeHandler, so match.data was a route
record { route, method, meta, handler }, while the generated app passes that value straight to h3
as middleware. Global middleware in the same file already uses serializeHandlerFn, which emits the
bare handler — this makes routed middleware do the same, since the matcher's payload is middleware
rather than a route.

The alternative would be to unwrap on the consumer side in virtual/app.ts (.map((r) => r.data.handler)),
but the route/method/meta fields are never read for middleware, so emitting them at all is the
part that's wrong. Fixing the serializer also keeps the payload correct for any future consumer.

Regression test first, per AGENTS.md: the fixture gains a global middleware and a route-scoped one
that record the order they run in, and test/tests.ts asserts ["rules", "global", "routed"], so the
test covers both the crash and the documented ordering. It runs against every preset. Reverting just
the one-word change in routing.ts makes it fail with the same fn is not a function.

There was no test for route-scoped middleware anywhere in the repo before this, which is the reason
the breakage survived — the mismatch is present at least as far back as d37caec (2025-12-11).

Verified on this branch with pnpm lint, pnpm typecheck, and the full suite against both builders:
882 passed. The one failure, test/unit/bump-version.test.ts, also fails on a clean main checkout
in a non-UTC timezone and is unrelated.

📝 Checklist

`findRoutedMiddleware` wrapped each match as `{ route, handler }` while the
app passed `match.data` straight to h3 as middleware, so any handler
registered with `middleware: true` and a route pattern failed with
`fn is not a function`. Serialize the bare handler, matching the
`MatchedRoute<Middleware>[]` contract, and cover the rules -> global ->
routed order in the fixture.
@ShreeBohara
ShreeBohara requested a review from pi0 as a code owner August 24, 2026 17:02
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

@ShreeBohara is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

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: 1f53e8c3-28a8-45ac-bf98-adb4cca6999f

📥 Commits

Reviewing files that changed from the base of the PR and between e36e7a6 and 55f622c.

📒 Files selected for processing (5)
  • src/build/virtual/routing.ts
  • test/fixture/nitro.config.ts
  • test/fixture/server/middleware/order.ts
  • test/fixture/server/routed-middleware/order.ts
  • test/tests.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The routing compiler now emits callable routed middleware handlers. The test fixture adds a route-scoped middleware endpoint and records execution order. The regression test verifies rules, global, and routed execution plus the existing response header.

Changes

Route-scoped middleware

Layer / File(s) Summary
Routed handler serialization
src/build/virtual/routing.ts
findRoutedMiddleware now uses serializeHandlerFn and retains matchAll: true.
Middleware order regression coverage
test/fixture/nitro.config.ts, test/fixture/server/middleware/order.ts, test/fixture/server/routed-middleware/order.ts, test/tests.ts
The fixture registers /api/middleware-order, records middleware execution, and verifies the sequence rules, global, routed with the x-test response header.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 55f62

The change makes route-scoped middleware receive callable handlers and adds regression coverage for execution order and the prior failure. No actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits syntax and accurately describes the routing serializer fix.
Description check ✅ Passed The description clearly explains the route-scoped middleware failure, fix, regression test, and verification results.
Linked Issues check ✅ Passed The changes fix issue #4557 by serializing bare middleware handlers and add regression coverage for middleware execution and ordering.
Out of Scope Changes check ✅ Passed All changes support issue #4557 by implementing the serializer fix and adding focused fixture and regression-test coverage.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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.

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4558

commit: 55f622c

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.

Route-scoped middleware throws fn is not a function and returns 500

1 participant