next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Next.js TypeError: Cannot read properties of undefined (reading 'bind') - caused by middleware.ts

Open mstys opened this issue 2 years ago • 28 comments

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 22.6.0: Wed Jul  5 22:21:56 PDT 2023; root:xnu-8796.141.3~6/RELEASE_X86_64
Binaries:
  Node: 16.13.1
  npm: 8.19.2
  Yarn: 1.22.11
  pnpm: N/A
Relevant Packages:
  next: 13.5.4
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: N/A
Next.js Config:
  output: standalone

Which example does this report relate to?

https://github.com/vercel/next.js/blob/canary/examples/with-docker/README.md

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

I getting following error on run next app after npm run build

(node:50480) ExperimentalWarning: stream/web is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
 ⚠ "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
  ▲ Next.js 13.5.4
  - Local:        http://localhost:3000

 ✓ Ready in 257ms
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/Users/michal.stys/OwnProjects/next13-test/node_modules/next/dist/server/base-server.js:389:50)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/Users/michal.stys/OwnProjects/next13-test/node_modules/next/dist/server/base-server.js:389:50)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

My middleware.ts from next.js docs.

import { NextRequest, NextResponse } from "next/server";

const PUBLIC_FILE = /\.(.*)$/;

export async function middleware(req: NextRequest) {
  if (
    req.nextUrl.pathname.startsWith("/_next") ||
    req.nextUrl.pathname.includes("/api/") ||
    PUBLIC_FILE.test(req.nextUrl.pathname)
  ) {
    return;
  }

  if (req.nextUrl.locale === "default") {
    const locale = "en";
    return NextResponse.redirect(
      new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
    );
  }
}

PS. all works perfect without this middleware

Expected Behavior

Type error doesn't exists if using middleware.ts

To Reproduce

npx create-next-app --example with-docker nextjs-docker

// add middleware.ts added above

npm run build
npm start

NEXT-1739

mstys avatar Oct 03 '23 15:10 mstys

I also started to see this today after I upgrade Next.js to 13.5.4 image

Phoenix-Alpha avatar Oct 04 '23 08:10 Phoenix-Alpha

same issue

Lukacs5 avatar Oct 04 '23 16:10 Lukacs5

There's a warning from the console, please run the standalone server instead

"next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.

huozhi avatar Oct 04 '23 22:10 huozhi

@huozhi it's warning not error. If you think that it works as expected it should throw error and not start. "next start" does not work with "output: standalone" configuration. - means that standalone features are not running , not full Next app.

Moreover app works correctly without middleware.

mstys avatar Oct 06 '23 08:10 mstys

@huozhi I tested it standalone mode as well before I created an issue, and got following error:

➜  next13-test git:(main) ✗ node .next/standalone/server.js
(node:94767) ExperimentalWarning: stream/web is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
  ▲ Next.js 13.5.4
  - Local:        http://localhost:3000
  - Network:      http://0.0.0.0:3000

 ✓ Ready in 124ms
[
  {
    label: 'Your personal data',
    fields: [
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object]
    ]
  }
]
{ list: [ { label: 'Your personal data', fields: [Array] } ] }
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/Users/michal.stys/OwnProjects/next13-test/.next/standalone/node_modules/next/dist/server/base-server.js:389:50)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/Users/michal.stys/OwnProjects/next13-test/.next/standalone/node_modules/next/dist/server/base-server.js:389:50)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

mstys avatar Oct 06 '23 09:10 mstys

@huozhi, this still exists - not sure why it's closed. This break features based on middleware and have other problem on Vercel, like sharp module not found even though it's added as dependency in package.json

Phoenix-Alpha avatar Oct 06 '23 19:10 Phoenix-Alpha

@mstys I couldn't repro that error with with-docker example and that middleware

➜  nextjs-docker git:(main) ✗ node ./.next/standalone/server.js
  ▲ Next.js 13.5.4
  - Local:        http://localhost:3000
  - Network:      http://0.0.0.0:3000

 ✓ Ready in 36ms

huozhi avatar Oct 06 '23 21:10 huozhi

@Phoenix-Alpha sharp module not found sounds like a different issue, unrelated to this. Please open a new issue with reproduction

huozhi avatar Oct 06 '23 21:10 huozhi

@huozhi you add middleware to project?

// middleware.ts

import { NextRequest, NextResponse } from "next/server";

const PUBLIC_FILE = /\.(.*)$/;

export async function middleware(req: NextRequest) {
  if (
    req.nextUrl.pathname.startsWith("/_next") ||
    req.nextUrl.pathname.includes("/api/") ||
    PUBLIC_FILE.test(req.nextUrl.pathname)
  ) {
    return;
  }

  if (req.nextUrl.locale === "default") {
    const locale = "en";
    return NextResponse.redirect(
      new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
    );
  }
}

then try again

mstys avatar Oct 16 '23 08:10 mstys

I did, I cannot repro it

huozhi avatar Oct 18 '23 22:10 huozhi

The bug is reproducible on Node.js 19 and above, with bare next app (obtained frompnpm create next-app) with the simplest middleware:

import { NextResponse } from "next/server";

export function middleware() {
  return NextResponse.next();
}

I got it on Node.js 20 (It will become the LTS on 24 of October) and with the unset output field in next.config.js

psd-coder avatar Oct 20 '23 16:10 psd-coder

I ran into this error as well. I could reproduce it only if I put the middleware.js file in root (I used the with-docker repo). docker build -t nextjs-docker .

docker run -p 3000:3000 nextjs-docker
  ▲ Next.js 13.5.6
  - Local:        http://localhost:3000
  - Network:      http://0.0.0.0:3000

 ✓ Ready in 158ms
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/app/node_modules/next/dist/server/base-server.js:389:50)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
TypeError: Cannot read properties of undefined (reading 'bind')
    at NextNodeServer.handleRequestImpl (/app/node_modules/next/dist/server/base-server.js:389:50)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

However when I renamed the file from middleware.js to _middlewere.js the error dissapered. I tired this in my own project and the renaming indeed removes the error. I haven't ran all tests yet but I'll continue investigate this further tomorrow.

From the docs we can read:

For example, a Middleware at pages/about/_middleware.ts can move the logic to /middleware.ts in the root of your repository. Then, a conditional statement can be used to only run the Middleware when it matches the about/* path:

Is it possible it should say "/_middleware.(ts/js)" perhaps?

Here is a minimal reproduction of the behaviour: nextjs-docker.zip

jjojo avatar Oct 26 '23 14:10 jjojo

I am running to the same issue on Node.js v18.15.0

kherona avatar Oct 31 '23 02:10 kherona

For me, the issue was that the middleware was being applied to my /ws (custom websocket) endpoint. I don't need any middleware on that endpoint, so adding this to middleware.ts fixes it:

export const config = {
  matcher: '/((?!ws$).*)', // match all paths except /ws
}

smartinio avatar Nov 02 '23 01:11 smartinio

Same issue here, it will fix in the future right? I saw a similar issue closed (issues/55802)

spencerchang avatar Nov 10 '23 04:11 spencerchang

I think I might be know what is happening in most of the cases with this @spencerchang @mstys . Did you have a browser tab open with the app left running in dev mode? (Given HMR tries to connect over websockets)

This error seems to occur when trying to connect to a standalone server in websocket mode with middleware enabled.

the handleRequestImpl method assumes that the passed res._res is always going to be a ServerResponse image

but can be passed as a socket when calling the endpoint as a websocket: image

(Try calling standalone server with new WebSocket ( "ws://127.0.0.1:3000" ) from a browser tab)

Think it might be worth excluding anything trying to connect over ws:// as a whole from being run as middleware @huozhi given the assumptions made in the current code? :thinking:

ryanolee avatar Nov 20 '23 13:11 ryanolee

next.js 14.0.4 this issue still happened.

spencerchang avatar Dec 08 '23 05:12 spencerchang

I experienced this error message earlier after upgrading to Next v14 — i needed to upgrade my Clerk package, it turned out. The error went away after.

Check any middleware that your middleware may be using.

tyler-dot-earth avatar Dec 08 '23 05:12 tyler-dot-earth

$ /app/node_modules/.bin/next info

Operating System:
  Platform: linux
  Arch: x64
  Version: #82-Ubuntu SMP Tue Jun 6 23:10:23 UTC 2023
Binaries:
  Node: 18.17.1
  npm: 9.6.7
  Yarn: 1.22.19
  pnpm: N/A
Relevant Packages:
  next: 13.5.6
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.2.2
Next.js Config:
  output: N/A


warn  - Latest canary version not detected, detected: "13.5.6", newest: "14.0.5-canary.5".
        Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
        Read more - https://nextjs.org/docs/messages/opening-an-issue
Done in 1.62s.

I encountered the same issue today using 13.5.6. No matter what I did, nothing fixed the error. So I started building from scratch, and I rm -fr .next, next build it and next start in each step below.

  1. I created another directly
  2. created a minimal next project running (no issues here)
  3. added middleware.ts from the original (no issues here)
  4. added pages/_app.tsx from the original (no issues here)
  5. added pages/api directly from the original (no issues here)
  6. added pages/* from the original (no issues here)
  7. ... so I added all including yarn.lock, except .next node_modules from the original (no issues here)
  8. ?????

So I don't know why and how the error is gone, but I do not see the TypeError: Cannot read properties of undefined (reading 'bind') repeating in my log anymore...

I surely see this at 389 in node_modules/next/dist/server/base-server.js though.

const origSetHeader = _res.setHeader.bind(_res);

github0013 avatar Dec 11 '23 07:12 github0013

I today had this happening locally and it drove me crazy. Then I realized I had a dev-instance of the app open in a tab, that tried to make websocket requests to the prod app, that doesn't support websockets. So.. false alert :sweat_smile:

VanCoding avatar Dec 20 '23 14:12 VanCoding

I'm also facing same issue: ⨯ TypeError: Cannot read properties of undefined (reading 'bind') at NextNodeServer.handleRequestImpl

Node version: 20.10.0, 18.18.0 Next verson: 14.0.4 app-router

naseef0 avatar Jan 04 '24 12:01 naseef0

If you're using fallbacks on dynamic pages (i.e., pages like [componentId.jsx] or [componentIdNameDirectory]/index.jsx), set fallback to 'blocking'.

E.g.:

return {
        fallback: 'blocking',
        paths: meetups.map((meetup) => (
            { params: { meetupId: meetup._id.toString(),
            }
    }))
    }

This should fix the issue.

rodhis avatar Jan 11 '24 18:01 rodhis

I had this problem after upgrading to 14.1. It didn't happen in 13.4.2 before the upgrade. After deleting middleware.ts the error disappeared Is there any workaround?

ya2s avatar Jan 19 '24 13:01 ya2s

@huozhi @ztanner @agustints I was able to reproduce the problem with minimal configuration Reproduce by starting locally and accessing localhost:3000/test https://github.com/yamatsum/nextjs-14.1-sample

ya2s avatar Jan 26 '24 11:01 ya2s

@yamatsum you succeed with finding some solution? I have the same problem with next 14.0.4 and I don't know why

ofirelarat avatar Jan 30 '24 08:01 ofirelarat

No, it's not resolved yet I'm having trouble updating

ya2s avatar Jan 30 '24 15:01 ya2s

Hi @yamatsum, thanks for sharing, next weekend I will try to reproduce it with your repo and see if I can help fix this issue (I don't promise anything, I will try to do my best to help you with this)!

Agustín Tornielli, Software Developer

agustints avatar Jan 31 '24 21:01 agustints

In my case, it's happened when i include socket.io and enable websocket. I have no idea to fix it.

spencerchang avatar Feb 01 '24 02:02 spencerchang

after I've added export const config = { matcher: [ '/((?!api|_next/static|_next/image|favicon.ico).*)', ], } this bug disapiered on 14.1

webmak avatar Feb 03 '24 14:02 webmak

In your reproduction @yamatsum, since you're using a multi-zone approach, when loading /test the dev HMR websocket for web2 is being handled by your middleware in apps/web rather than making it to the server it was intended for (apps/web2). Updating your middleware matcher to exclude paths that correspond the basepath of the other server you're rewriting to (ie anything that starts with /test) will fix the problem. Something like this:

// apps/web/middleware.ts
export const config = {
  matcher: [
    // Don't handle HMR requests for the dev server we rewrite to
    "/((?!test/_next/webpack-hmr).*)",
  ],
};

Note: It's currently important that you use matcher to exclude these paths, rather than skipping over them in the middleware handler itself.

When doing this, it will see that your middleware didn't handle the request, and move onto your rewrites which point the request to your other server.

If you're running into this issue but aren't running a multi-zone setup, then there's likely some other websocket upgrade request that is being handled by your middleware. As mentioned by some folks in earlier replies, make sure your middleware matchers are skipping over those routes so they can make it to the server they were intended for.

We should be able to detect this and handle it more gracefully on our side, so I can work on a fix for that. The above is a workaround in the meantime.

ztanner avatar Feb 04 '24 16:02 ztanner

@ztanner Thank you for investigating! Will the problem be fixed soon?

Also, is it necessary to exclude webpack-hmr?

ya2s avatar Feb 06 '24 13:02 ya2s