nextjs - ✅(Solved) Fix 500 errors when sending OPTIONS request to _next/static/chunks/... [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#92131Fetched 2026-04-08 01:51:51
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
0
Author
Timeline (top)
labeled ×5closed ×1commented ×1issue_type_added ×1

Error Message

Send OPTIONS request to one of those URLs instead of GET and note that you get a 500 error OPTIONS request should really be handled without any error, but if an error must be given then 405 or something else in the 4XX range would be much less frustrating.

PR fix notes

PR #92147: fix: return 405 for non-GET/HEAD requests to static files (#92141)

Description (problem / solution / changelog)

<!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->

What?

Return 405 Method Not Allowed instead of 500/400 for non-GET/HEAD requests (e.g. OPTIONS, POST) to /_next/static/ and /static/ paths.

Why?

Fixes #92141

In production mode (next start), sending a non-GET/HEAD request to a static file path caused incorrect responses:

  • OPTIONS400 — the render pipeline's blanket OPTIONS guard (base-server.ts:2397) overrode the 405 that router-server.ts intended to return via invokeRender
  • POST, PUT, etc.500 — the request fell through to the page rendering pipeline and crashed

Static files should only be served via GET or HEAD. Any other method should be cleanly rejected with 405 and an Allow: GET, HEAD header, per RFC 9110 §15.5.6.

How?

Two layers of fix:

  1. packages/next/src/server/lib/router-server.ts — Send the 405 response directly via res.end('Method Not Allowed') instead of calling invokeRender(). This avoids entering the render pipeline entirely, which was the root cause of the OPTIONS→400 override.

  2. packages/next/src/server/base-server.ts — Add a method check in renderImpl() before this.handleRequest() as defense-in-depth for custom server scenarios that call render() directly.

  3. test/production/options-request/options-request.test.ts — Added 7 test cases to the existing suite covering _next/static paths for GET, HEAD, OPTIONS, POST, PUT, DELETE, and PATCH.

Test Plan

  • All 14 tests pass (7 existing + 7 new) via pnpm test-start-turbo test/production/options-request/
  • GET / HEAD → 200
  • OPTIONS / POST / PUT / DELETE / PATCH → 405 with Allow: GET, HEAD header

Changed files

  • packages/next/src/server/base-server.ts (modified, +11/-0)
  • packages/next/src/server/lib/router-server.ts (modified, +3/-4)
  • test/production/options-request/options-request.test.ts (modified, +32/-0)

Code Example

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 32190
  Available CPU cores: 16
Binaries:
  Node: 22.14.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 16.2.1-canary.14 // Latest available version is detected (16.2.1-canary.14).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

Note that the same issue occurs on our GCP cloud run production instance
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/vercel/next.js/tree/canary/examples/reproduction-template

To Reproduce

Start the application in production mode (npm run build && npm run start)

Open localhost:3000 and filter network tab of dev console for _next/static/chunks

Send OPTIONS request to one of those URLs instead of GET and note that you get a 500 error

Current vs. Expected behavior

500 errors should always be considered a bug somewhere in the code, as potentially malicious or broken clients should not be able to trigger them arbitrarily. Currently it is polluting our HTTP logs with noise and makes up the almost all of our 500 errors in production.

OPTIONS request should really be handled without any error, but if an error must be given then 405 or something else in the 4XX range would be much less frustrating.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 32190
  Available CPU cores: 16
Binaries:
  Node: 22.14.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 16.2.1-canary.14 // Latest available version is detected (16.2.1-canary.14).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

Note that the same issue occurs on our GCP cloud run production instance

Which area(s) are affected? (Select all that apply)

create-next-app, Metadata, Output, Route Handlers

Which stage(s) are affected? (Select all that apply)

next start (local), Other (Deployed)

Additional context

Wasn't really sure what to put for areas affected, but basically just about all nextjs instances out in the wild can be tricked into 500-ing, and we have seen that certain questionable bots will do this automatically, whether intentional or not.

extent analysis

Fix Plan

To fix the issue of 500 errors on OPTIONS requests, we need to add a catch-all route to handle these requests.

Here are the steps:

  • Create a new file pages/api/options.js with the following content:
export default async function handler(req, res) {
  return res.status(405).end();
}
  • Alternatively, you can also add a middleware to handle OPTIONS requests for all routes:
// middleware/options.js
export default async function optionsMiddleware(req, res, next) {
  if (req.method === 'OPTIONS') {
    return res.status(405).end();
  }
  return next();
}
  • Then, add this middleware to your Next.js pages:
// pages/_app.js
import optionsMiddleware from '../middleware/options';

function MyApp({ Component, pageProps }) {
  optionsMiddleware();
  return <Component {...pageProps} />;
}

However, a more straightforward approach would be to use the next.config.js file to add a catch-all route for OPTIONS requests:

// next.config.js
module.exports = {
  //... other configurations ...
  async rewrites() {
    return [
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'X-Method-Override',
            value: 'OPTIONS',
          },
          {
            type: 'method',
            value: 'OPTIONS',
          },
        ],
        destination: '/api/options',
      },
    ];
  },
};

And then create the pages/api/options.js file as mentioned earlier.

Verification

To verify that the fix worked, send an OPTIONS request to one of the _next/static/chunks URLs and check that the response status code is 405 instead of 500.

Extra Tips

  • Make sure to test your application thoroughly after applying this fix to ensure that it doesn't introduce any other issues.
  • Consider adding logging to track when the OPTIONS request handler is triggered to monitor for any potential abuse.
  • If you're using a load balancer or reverse proxy, ensure that it's configured to pass through OPTIONS requests correctly.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix 500 errors when sending OPTIONS request to _next/static/chunks/... [1 pull requests, 1 comments, 2 participants]