Skip to content

fix(middleware): make an invalid root middleware export say how to fix it (depends on #2999) - #3011

Merged
kwakayama merged 1 commit into
mainfrom
fix/actionable-middleware-export-error
Jul 22, 2026
Merged

fix(middleware): make an invalid root middleware export say how to fix it (depends on #2999)#3011
kwakayama merged 1 commit into
mainfrom
fix/actionable-middleware-export-error

Conversation

@mattboon

@mattboon mattboon commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

A root middleware.ts using a named middleware export follows a common external convention, but Veryfront expects a default middleware function or a non-empty default array. Before this PR, strict middleware loading failed with a generic export-shape error that did not identify the file, the exported names, or the expected signature.

This keeps invalid global middleware fail-closed, but makes the error actionable: it names middleware.ts, detects the named middleware export case, lists wrong exports otherwise, shows the (c, next) default-export shape, and points to docs/guides/middleware.md.

Verification

  • deno test --allow-all src/server/dev-server/middleware.test.ts
  • deno task lint:sanitizer-baseline
  • deno task lint
  • deno task typecheck

Review status

Score: 93/100. Recommended next step: merge after GitHub required checks finish green.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8690a44105

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/server/dev-server/middleware.ts Outdated
const detail = looksLikeNext
? `Found a named "middleware" export, which is the Next.js convention. ` +
`Veryfront expects a default export, and its middleware receives ` +
`(c, next) — a context carrying c.req, not the Request itself.`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace the em dash in the middleware error copy

When this invalid root middleware path is hit, the new user-facing TypeError includes the U+2014 em dash in (c, next) — a context...; the repo's public copy rules apply to error messages and require ASCII punctuation instead, so this text should use a comma or period before shipping.

AGENTS.md reference: AGENTS.md:L43-L55

Useful? React with 👍 / 👎.

@kwakayama kwakayama left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Score: 70/100

Requesting changes. The runtime change is low-risk and the diagnostic is much better, but the PR currently fails typechecking.

Blocking issue:

  • src/server/dev-server/middleware.test.ts:96 and :111 read error.message from the value returned by assertRejects, but in this wrapper the value is typed as unknown. Local deno test typechecking fails with TS18046.

Please narrow before reading the message, for example by asserting error instanceof TypeError, or use the project’s typed assertion pattern.

This PR is also stacked on lower open PRs and only shows CLA in the status rollup, so it is not merge-ready even after the local type error is fixed.

@mattboon
mattboon force-pushed the fix/ctx-json-parses-request-body branch from c5ea111 to d223eeb Compare July 21, 2026 19:23
@mattboon
mattboon force-pushed the fix/actionable-middleware-export-error branch from 9e4342a to cc313eb Compare July 21, 2026 19:23
@mattboon
mattboon force-pushed the fix/ctx-json-parses-request-body branch from d223eeb to 10b0811 Compare July 21, 2026 19:44
@mattboon
mattboon force-pushed the fix/actionable-middleware-export-error branch from cc313eb to 68ad259 Compare July 21, 2026 19:44
@mattboon

Copy link
Copy Markdown
Collaborator Author

Addressed. Both sites now narrow with assertInstanceOf(error, TypeError) from #veryfront/testing/assert.ts before reading .message.

That helper is declared asserts actual is T, so it narrows unknown at the type level and checks at runtime, which covers both halves of your suggestion in one call. It is also the pattern already used for this exact purpose elsewhere in the repo (src/security/input-validation/handler.test.ts:179). The alternative idiom here (... as Error) silences TS18046 without asserting anything, so I did not use it.

All eight message assertions are unchanged, so the coverage that matters for this PR, the error copy itself, is intact: the file name, the Next.js convention, the (c, next) signature, export default, the docs link, and the Found export(s): branch.

Verification: deno check src/server/dev-server/middleware.test.ts clean (was 8x TS18046); suite 8 steps passing; deno check on the non-test file in the commit clean; deno fmt/deno lint clean.

@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from 10b0811 to 6490cad Compare July 21, 2026 20:30
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 68ad259 to 01e3d5e Compare July 21, 2026 20:30
kwakayama
kwakayama previously approved these changes Jul 21, 2026

@kwakayama kwakayama left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Follow-up after fixes: approving. The thrown-value handling now narrows the caught error before reading . Local verification: \running 2 tests from ./src/server/dev-server/middleware.test.ts
loadMiddlewareFile ...
fails closed for invalid production middleware ...
------- output -------
✘ [ERROR] Expected identifier but found end of file

../../../../app/middleware.ts:1:33:
  1 │ export default function broken( {
    ╵                                  ^

22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Build failed with 1 error:
../../../../app/middleware.ts:1:33: ERROR: Expected identifier but found end of file
----- output end -----
fails closed for invalid production middleware ... ok (17ms)
fails closed when production middleware has no valid default export ...
------- output -------
22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Invalid middleware export in middleware.ts. Found a named "middleware" export, which is the Next.js convention. Veryfront expects a default export, and its middleware receives (c, next), where c is a context carrying c.req, not the Request itself.
Expected a default export that is a middleware function, or a non-empty array of them:

export default async function middleware(c, next) {
const response = await next();
return response;
}

See docs/guides/middleware.md.
----- output end -----
fails closed when production middleware has no valid default export ... ok (4ms)
fails closed when a production middleware array contains invalid entries ...
------- output -------
22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Invalid middleware export in middleware.ts. Found export(s): default.
Expected a default export that is a middleware function, or a non-empty array of them:

export default async function middleware(c, next) {
const response = await next();
return response;
}

See docs/guides/middleware.md.
----- output end -----
fails closed when a production middleware array contains invalid entries ... ok (2ms)
preserves nonfatal development loading for invalid middleware ...
------- output -------
✘ [ERROR] Expected identifier but found end of file

../../../../app/middleware.ts:1:33:
  1 │ export default function broken( {
    ╵                                  ^

22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Build failed with 1 error:
../../../../app/middleware.ts:1:33: ERROR: Expected identifier but found end of file
----- output end -----
preserves nonfatal development loading for invalid middleware ... ok (1ms)
loadMiddlewareFile ... ok (25ms)
dev-server/middleware: actionable rejection ...
names the Next.js convention when a named middleware export is found ...
------- output -------
22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Invalid middleware export in middleware.ts. Found a named "middleware" export, which is the Next.js convention. Veryfront expects a default export, and its middleware receives (c, next), where c is a context carrying c.req, not the Request itself.
Expected a default export that is a middleware function, or a non-empty array of them:

export default async function middleware(c, next) {
const response = await next();
return response;
}

See docs/guides/middleware.md.
----- output end -----
names the Next.js convention when a named middleware export is found ... ok (11ms)
lists the offending exports when the shape is merely wrong ...
------- output -------
22:30:19 SERVER ▲ [middleware] Failed to load middleware.ts: Invalid middleware export in middleware.ts. Found export(s): handler, other.
Expected a default export that is a middleware function, or a non-empty array of them:

export default async function middleware(c, next) {
const response = await next();
return response;
}

See docs/guides/middleware.md.
----- output end -----
lists the offending exports when the shape is merely wrong ... ok (2ms)
still accepts a valid default export ... ok (2ms)
still accepts an array of functions ... ok (3ms)
dev-server/middleware: actionable rejection ... ok (18ms)

ok | 2 passed (8 steps) | 0 failed (46ms). Score: 92/100. Next step: merge after base stack and checks are green.

@kwakayama

Copy link
Copy Markdown
Contributor

Clean follow-up after the approval above:

Score: 92/100.

Verification:

  • deno test --allow-all src/server/dev-server/middleware.test.ts

Next step: merge after the base stack and refreshed checks are green.

@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from 6490cad to 84b9305 Compare July 21, 2026 20:38
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 01e3d5e to 5f3ef56 Compare July 21, 2026 20:38
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from a829396 to f4f212a Compare July 21, 2026 22:39
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from c14432c to c1fac99 Compare July 21, 2026 22:39
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from f4f212a to 4bc6a04 Compare July 21, 2026 22:47
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch 2 times, most recently from 1f6c198 to 666f02f Compare July 21, 2026 22:57
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch 2 times, most recently from 7ea42f9 to 1beb02b Compare July 21, 2026 23:38
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch 2 times, most recently from 0d05b5d to e4c7014 Compare July 21, 2026 23:44
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch 2 times, most recently from 153b882 to 7811905 Compare July 21, 2026 23:53
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from e4c7014 to 78cd493 Compare July 21, 2026 23:53
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from 7811905 to e321644 Compare July 22, 2026 00:15
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 78cd493 to 7c589d3 Compare July 22, 2026 00:15
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from e321644 to bb3bcde Compare July 22, 2026 00:22
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch 2 times, most recently from 1dbff3b to b7ebd4b Compare July 22, 2026 00:29
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from bb3bcde to a3ed383 Compare July 22, 2026 00:29
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from b7ebd4b to e4f1cce Compare July 22, 2026 00:43
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch 2 times, most recently from e0f731f to 4eaf654 Compare July 22, 2026 00:47
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch 2 times, most recently from 5874fea to 2aa1463 Compare July 22, 2026 00:54
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch from 4eaf654 to 3e8f040 Compare July 22, 2026 00:54
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 2aa1463 to 9e4d6c7 Compare July 22, 2026 01:04
@kwakayama
kwakayama force-pushed the fix/ctx-json-parses-request-body branch 2 times, most recently from d962947 to 82d10a5 Compare July 22, 2026 01:12
@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 9e4d6c7 to 7bb9253 Compare July 22, 2026 01:12
…x it

A root `middleware.ts` written to the Next.js convention (a named `middleware`
export) makes every single route 500, and the only diagnostic was:

    Invalid middleware export: expected a function or non-empty array of functions

That names no file, no offending export, and no expected signature — so the
reasonable conclusion, and the one the reproducer reached, is that Veryfront has
no root middleware convention at all. It does, and it is documented; the error
just never pointed at it.

The message now names the file, lists what the module actually exported,
recognises the Next.js shape explicitly, shows the expected `(c, next)`
signature, and cites docs/guides/middleware.md.

Fixes bug 11 of the reproducer matrix.
Base automatically changed from fix/ctx-json-parses-request-body to main July 22, 2026 01:17
@kwakayama
kwakayama dismissed their stale review July 22, 2026 01:17

The base branch was changed.

@kwakayama
kwakayama force-pushed the fix/actionable-middleware-export-error branch from 7bb9253 to 8dad0c5 Compare July 22, 2026 01:18

@kwakayama kwakayama left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Score: 93/100

Critical review result: this solves a real operational bug. A mis-shaped root middleware.ts takes down every route, so the old generic error forced users to infer the convention from source. The fix preserves fail-closed behavior, but now names the source file, distinguishes the named middleware export case, lists wrong exports for other shapes, and shows the expected default export signature.

Validation reviewed:

  • deno test --allow-all src/server/dev-server/middleware.test.ts
  • deno task lint:sanitizer-baseline
  • deno task lint
  • deno task typecheck

Recommended next step: merge after GitHub required checks complete green.

@kwakayama
kwakayama enabled auto-merge (squash) July 22, 2026 01:19
@kwakayama
kwakayama merged commit 18d587c into main Jul 22, 2026
28 checks passed
@kwakayama
kwakayama deleted the fix/actionable-middleware-export-error branch July 22, 2026 01:23
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.

3 participants