vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.89k stars 26.98k forks source link

Using Undici as node fetch polyfill causes fetch failed #48744

Closed kaloyanBozhkov closed 1 year ago

kaloyanBozhkov commented 1 year ago

Verify canary release

Provide environment information

N/A

Which area(s) of Next.js are affected? (leave empty if unsure)

Data fetching (gS(S)P, getInitialProps)

Link to the code that reproduces this issue

https://github.com/vercel/next.js/blob/e601a3b53292278e1b7d1ef1f692ed340ef8be10/packages/next/src/server/node-polyfill-fetch.ts#L6

To Reproduce

Ensure project is using serverless functions that are from the frankfurt network (so far I know this one causes the problem, but maybe others do as well)

image

Below are my steps, but they should be entirely optional since replicating this is possible in different ways. 1) have a next api endpoint that fires a tRCP call using tRPC's client

2) call the endpoint

3) observe that fetch failed because of undici (node fetch polyfill)

Describe the Bug

Big thanks to TillaTheHun0 for reporting this.

I want to make a bug report since I replicated and can confirm his thesis.

Next has a node polyfill for fetch, which uses either undici or node-fetch depending on an environment variable called __NEXT_USE_UNDICI. This env variable is likely set by Vercel depending on which network the Serverless Functions are configured to execute on.

I tested countless times, and the thing that solved my problems was indeed changing the network location of my serverless functions in my Project Settings on Vercel.

Undici currently has some issue (RequestContentLengthMismatchError), partially documented here. This issue is causing all sorts of problems from different places since this fetch polyfill is used by many other tools.

In my case it was tRPC complaining, with:

 TRPCClientError: fetch failed
    at TRPCClientError.from (file:///var/task/node_modules/@trpc/client/dist/transformResult-6fb67924.mjs:13:16)
    at file:///var/task/node_modules/@trpc/client/dist/links/httpBatchLink.mjs:211:64 {
  meta: undefined,
  shape: undefined,
  data: undefined,
  [cause]: TypeError: fetch failed
      at Object.fetch (node:internal/deps/undici/undici:14062:11) {
    cause: RequestContentLengthMismatchError: Request body length does not match content-length header
        at AsyncWriter.end (node:internal/deps/undici/undici:9704:19)
        at writeIterable (node:internal/deps/undici/undici:9614:16) {
      code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
    }
  }
}

though I read around different places people encountering the same problem in various ways.

We should either use only one polyfill (the working one) while waiting for undici to be patched, or we should allow people to explicitly choose which polyfill they'd like through configuring __NEXT_USE_UNDICI somewhere. Though I have a feeling that going with either option could be impossible if there's unknown limitations to the machine running the Functions that make it so undici is chosen over node-fetch.

Regardless, it is currently a fact that the "Project Settings" > "Functions" page (on Vercel) does not have any information about this behaviour. At the very least we should inform users that there's environment variables that could change depending on the chosen region for the Serverless Functions. Optimally we should provide a list with environment variables and their configuration for the different regions, and ideally also how these map to certain behaviours. At the very least this would speed up debugging and problem solving IMO. (this part might not be specific to the Next repo though)

Expected Behavior

fetch requests should not fail like this, regardless of which serverless function they are running on.

Which browser are you using? (if relevant)

N/A

How are you deploying your application? (if relevant)

N/A

jackycymo commented 1 year ago

+1 to this. I'm on 14.0.5-canary and getting this error on Vercel during build.

I'm using Apollo Client Nextjs for useSuspenseQuery() / rsc query in static pages and the error happens during build when pre-rendering the page.

This error doesn't happen in local dev env.

ApolloError: fetch failed
--
20:39:09.889 | at new ApolloError (/vercel/path0/app/.next/server/chunks/7756.js:120721:28)
20:39:09.889 | at /vercel/path0/app/.next/server/chunks/7756.js:120181:19
20:39:09.890 | at both (/vercel/path0/app/.next/server/chunks/7756.js:124244:53)
20:39:09.890 | at /vercel/path0/app/.next/server/chunks/7756.js:124237:72
20:39:09.890 | at new Promise (<anonymous>)
20:39:09.890 | at Object.then (/vercel/path0/app/.next/server/chunks/7756.js:124237:24)
20:39:09.890 | at Object.error (/vercel/path0/app/.next/server/chunks/7756.js:124245:49)
20:39:09.890 | at notifySubscription (/vercel/path0/app/.next/server/chunks/7756.js:93242:18)
20:39:09.890 | at onNotify (/vercel/path0/app/.next/server/chunks/7756.js:93281:3)
20:39:09.890 | at SubscriptionObserver.error (/vercel/path0/app/.next/server/chunks/7756.js:93342:7) {
20:39:09.890 | graphQLErrors: [],
20:39:09.890 | protocolErrors: [],
20:39:09.890 | clientErrors: [],
20:39:09.890 | networkError: TypeError: fetch failed
20:39:09.890 | at Object.fetch (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:26669) {
20:39:09.890 | cause: RequestContentLengthMismatchError: Request body length does not match content-length header
20:39:09.890 | at AsyncWriter.end (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:71966)
20:39:09.890 | at writeIterable (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:70638) {
20:39:09.890 | code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
20:39:09.890 | }
20:39:09.890 | },
20:39:09.891 | extraInfo: undefined
20:39:09.891 | }
kaloyanBozhkov commented 1 year ago

+1 to this. I'm on 14.0.5-canary and getting this error on Vercel during build.

I'm using Apollo Client Nextjs for useSuspenseQuery() / rsc query in static pages and the error happens during build when pre-rendering the page.

This error doesn't happen in local dev env.

ApolloError: fetch failed
--
20:39:09.889 | at new ApolloError (/vercel/path0/app/.next/server/chunks/7756.js:120721:28)
20:39:09.889 | at /vercel/path0/app/.next/server/chunks/7756.js:120181:19
20:39:09.890 | at both (/vercel/path0/app/.next/server/chunks/7756.js:124244:53)
20:39:09.890 | at /vercel/path0/app/.next/server/chunks/7756.js:124237:72
20:39:09.890 | at new Promise (<anonymous>)
20:39:09.890 | at Object.then (/vercel/path0/app/.next/server/chunks/7756.js:124237:24)
20:39:09.890 | at Object.error (/vercel/path0/app/.next/server/chunks/7756.js:124245:49)
20:39:09.890 | at notifySubscription (/vercel/path0/app/.next/server/chunks/7756.js:93242:18)
20:39:09.890 | at onNotify (/vercel/path0/app/.next/server/chunks/7756.js:93281:3)
20:39:09.890 | at SubscriptionObserver.error (/vercel/path0/app/.next/server/chunks/7756.js:93342:7) {
20:39:09.890 | graphQLErrors: [],
20:39:09.890 | protocolErrors: [],
20:39:09.890 | clientErrors: [],
20:39:09.890 | networkError: TypeError: fetch failed
20:39:09.890 | at Object.fetch (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:26669) {
20:39:09.890 | cause: RequestContentLengthMismatchError: Request body length does not match content-length header
20:39:09.890 | at AsyncWriter.end (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:71966)
20:39:09.890 | at writeIterable (/vercel/path0/app/node_modules/next/dist/compiled/undici/index.js:1:70638) {
20:39:09.890 | code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
20:39:09.890 | }
20:39:09.890 | },
20:39:09.891 | extraInfo: undefined
20:39:09.891 | }

Someone even made a demo showcasing this issue, bless them

https://github.com/vercel/vercel/issues/9690#issuecomment-1532387982

julioxavierr commented 1 year ago

Any known workaround for this?

nevolgograd commented 1 year ago

@julioxavierr using node-fetch solves this problem, but unfortunately it doesn't fit well as next fetch do.

croossin commented 1 year ago

Ran into similar issues - weirdly enough in iad1 Washington. After some googling, I stumbled across this article which recommended using fetch-ponyfill'. This fixed the issue for me.

kaloyanBozhkov commented 1 year ago

Ran into similar issues - weirdly enough in iad1 Washington. After some googling, I stumbled across this article which recommended using fetch-ponyfill'. This fixed the issue for me.

I wrote that, you're welcome :))

julioxavierr commented 1 year ago

Thanks @kaloyanBozhkov and @nevolgograd for this!

Unfortunately, it didn't solve my problem. I have an app with a middleware/auth layer using next-auth that also appears to use undici underneath. Did you encounter anything similar?

karl-run commented 1 year ago

I' m also seeing this error, but it seems to be in the context of a server action failing to redirect.

I have a server action that does this:

'use server'

export async function exampleAction() {
    const token = getToken(headers())

    await asyncFunction(...)

    redirect('/some-path')
}

Which throws:

failed to get redirect response TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (<app>/node_modules/next/dist/compiled/undici/index.js:1:67105)
      at _resume (<app>/node_modules/next/dist/compiled/undici/index.js:1:66726)
      at resume (<app>/node_modules/next/dist/compiled/undici/index.js:1:65413)
      at connect (<app>/node_modules/next/dist/compiled/undici/index.js:1:65301) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }
}
wladpaiva commented 1 year ago

Also having this issue in the redirect. I've created a reproduction here https://github.com/wladiston/reproduction-next-fetch-bug

It seems like if I pin next to 13.4.7 the error goes away.

masterkain commented 1 year ago

I started to see this too in server actions

  async function handleForm(formData: FormData) {
    'use server';
    const { error } = await updateProject(projectId, formData);

    const errorParam = error ? `&errorMessage=${error}` : '';
    redirect(`/projects/${projectId}/edit?tab=edit${errorParam}`);
  }
failed to get redirect response TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11522:11) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (/app/node_modules/next/dist/compiled/undici/index.js:1:67105)
      at _resume (/app/node_modules/next/dist/compiled/undici/index.js:1:66726)
      at resume (/app/node_modules/next/dist/compiled/undici/index.js:1:65413)
      at connect (/app/node_modules/next/dist/compiled/undici/index.js:1:65301) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }
}

content-length is 2 on the response but body is empty

Screenshot 2023-07-08 at 06 25 41
pavlovtech commented 1 year ago

I'm having the same issue with a redirect inside a server action

duylevietluu commented 1 year ago

I'm having the same issue as well.

andersbss commented 1 year ago

Same issue calling fetch in getServerSideProps using pages directory.

Function Region: Stockholm, Sweden (North) - arn1 Next version: 13.4.10 Node version: 18

TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:11457:11) at async ssrFetch (/var/task/dist/apps/hse/.next/server/chunks/9405.js:954:17) at async ssrFetchTmp (/var/task/dist/apps/hse/.next/server/chunks/3332.js:407:17) at async getServerSideProps.userTypes (/var/task/dist/apps/hse/.next/server/pages/revisions/[id].js:452:13) { cause: RequestContentLengthMismatchError: Request body length does not match content-length header at AsyncWriter.end (node:internal/deps/undici/undici:10241:19) at writeIterable (node:internal/deps/undici/undici:10149:16) { code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH' } } Error name: TypeError

aerinkim commented 1 year ago

facing the same issue in simple api writing to vercel postgres.

fetch failed: TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:11413:11) at async logObject (webpack-internal:///./pages/evalResult.tsx:44:26) { cause: RequestContentLengthMismatchError: Request body length does not match content-length header at AsyncWriter.end (/Users/aerinkim/Projects/lemma/node_modules/next/dist/compiled/undici/index.js:1:71966) at writeIterable (/Users/aerinkim/Projects/lemma/node_modules/next/dist/compiled/undici/index.js:1:70638) { code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH' } }

"next": "13.4.7", $ node -v v18.15.0

rumrum28 commented 1 year ago

same issue here

failed to get redirect response TypeError: fetch failed at Object.fetch (node:internal/deps/undici/undici:11413:11) { cause: RequestContentLengthMismatchError: Request body length does not match content-length header at write (C:\Users\Administrator\Desktop\Code\Next TUT\pryce-next\node_modules\next\dist\compiled\undici\index.js:1:67105) at _resume (C:\Users\Administrator\Desktop\Code\Next TUT\pryce-next\node_modules\next\dist\compiled\undici\index.js:1:66726) at resume (C:\Users\Administrator\Desktop\Code\Next TUT\pryce-next\node_modules\next\dist\compiled\undici\index.js:1:65413) at connect (C:\Users\Administrator\Desktop\Code\Next TUT\pryce-next\node_modules\next\dist\compiled\undici\index.js:1:65301) { code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH' } }

Gbuomprisco commented 1 year ago

I am also seeing the same issue when redirecting to a page from a server action

lorenzoa7 commented 1 year ago

I'm facing the same issue here

24jr commented 1 year ago

I am using fetch in a sveltekit server func and having I think this same issue

mqschwanda commented 1 year ago

I ran into this same issue when using redirect() inside a server action. I walked through a few Next versions to see where I would get the fix. I was finally able to solve this by downgrading Next as follows:

- "next": "^13.4.12",
+ "next": "13.4.7",

I have tested this fix with the development server inside a node:latest (v20.5.0) docker container and I am no longer runing into the error.

mihaiandrei97 commented 1 year ago

I ran into this same issue when using redirect() inside a server action. I walked through a few Next versions to see where I would get the fix. I was finally able to solve this by downgrading Next as follows:

- "next": "^13.4.12",
+ "next": "13.4.7",

I have tested this fix with the development server inside a node:latest (v20.5.0) docker container and I am no longer runing into the error.

+1 on this. Also having an issue while redirecting from a server action. Downgrading to 13.4.7 seems to fix it

raflymln commented 1 year ago

+1, needs to be fixed ASAP

rudden commented 1 year ago

Same issue here. Works on 13.4.7 but not on 13.4.13 (using signIn function from next-auth on a custom login page).

michaellukeread commented 1 year ago

Same issue with me - downgrading to 13.4.7 fixed it.

davecarlson commented 1 year ago

This started for me today too on 13.4.13

ChoaibMouhrach commented 1 year ago

Today, I encountered the identical error using version 13.4.13. While working in Postman, I unintentionally included a body in a GET request to my API handler. Consequently, the server produced the same error as mentioned by others earlier.

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11)
    at async invokeRequest (/home/camado/Desktop/coding/frameworks/next/yeralibrary/node_modules/.pnpm/next@13.4.13_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/server-ipc/invoke-request.js:21:12)
    at async requestHandler (/home/camado/Desktop/coding/frameworks/next/yeralibrary/node_modules/.pnpm/next@13.4.13_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/start-server.js:336:33)
    at async Server.<anonymous> (/home/camado/Desktop/coding/frameworks/next/yeralibrary/node_modules/.pnpm/next@13.4.13_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/start-server.js:152:13) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (node:internal/deps/undici/undici:9949:41)
      at _resume (node:internal/deps/undici/undici:9927:33)
      at resume (node:internal/deps/undici/undici:9829:7)
      at connect (node:internal/deps/undici/undici:9818:7) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }
}

Solution

Downgrading to version 13.4.7 solved the issue

0xc00010ff commented 1 year ago

Getting this locally when cloning the Supabase template https://vercel.com/templates/next.js/supabase. Reproducible on the login page which calls the form actions. 13.4.13

Screen Shot 2023-08-09 at 9 50 43 PM

Screen Shot 2023-08-09 at 9 51 01 PM
jstlaurent commented 1 year ago

I'm also getting the same error when sending a DELETE request with a Content-Length: 0 header, on 13.4.13.

This is the stacktrace:

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11457:11)
    at async invokeRequest (/Users/julien/projects/valence/polaris-hub/node_modules/next/dist/server/lib/server-ipc/invoke-request.js:21:12)
    at async requestHandler (/Users/julien/projects/valence/polaris-hub/node_modules/next/dist/server/lib/start-server.js:336:33)
    at async Server.<anonymous> (/Users/julien/projects/valence/polaris-hub/node_modules/next/dist/server/lib/start-server.js:152:13) {
  cause: RequestContentLengthMismatchError: Request body length does not match content-length header
      at write (node:internal/deps/undici/undici:9949:41)
      at _resume (node:internal/deps/undici/undici:9927:33)
      at resume (node:internal/deps/undici/undici:9829:7)
      at connect (node:internal/deps/undici/undici:9818:7) {
    code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH'
  }
}

Downgrading to 13.4.7 solves it.

Might be related to #51874, that landed in 13.4.8?

davecarlson commented 1 year ago

I have an inbound PR that fixes it

https://github.com/vercel/next.js/pull/53843

timneutkens commented 1 year ago

@davecarlson's PR was landed on stable 👍

switz commented 1 year ago

Seeing lots of undici issues across multiple projects on latest next and latest node 18:

Node.js v18.17.1
Static worker unexpectedly exited with code: 1 and signal: null
[    ] - info Generating static pages (3/9)node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

TypeError: terminated
    at Fetch.onAborted (node:internal/deps/undici/undici:11442:53)
    at Fetch.emit (node:events:514:28)
    at Fetch.terminate (node:internal/deps/undici/undici:10695:14)
    at Object.onError (node:internal/deps/undici/undici:11537:36)
    at Request.onError (node:internal/deps/undici/undici:8310:31)
    at errorRequest (node:internal/deps/undici/undici:10378:17)
    at Socket.onSocketClose (node:internal/deps/undici/undici:9811:9)
    at Socket.emit (node:events:514:28)
    at TCP.<anonymous> (node:net:323:12)
    at TCP.callbackTrampoline (node:internal/async_hooks:130:17) {
  [cause]: Error: write EPIPE
      at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:94:16)
      at WriteWrap.callbackTrampoline (node:internal/async_hooks:130:17)
}

Node.js v18.17.1
node:internal/deps/undici/undici:11576
    Error.captureStackTrace(err, this);
          ^

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11576:11) {
  cause: Error: write EPIPE
      at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:94:16)
      at WriteWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
    errno: -32,
    code: 'EPIPE',
    syscall: 'write'
  }
}
timneutkens commented 1 year ago

Keep in mind that Undici is the underlying name of fetch() in Node.js, so any error mentioning it could come from your own code as well. If you can provide a reproduction in a new issue we can have a look if it's something in Next.js.

pashazel commented 1 year ago

@timneutkens Hello, thanks for your work!

My steps to reproduce repo in the latest version: node 18.17.1 (node 20.5.1 same errors )/ next 13.4.16

~ npx create-next-app@latest
~ cd project
~ yarn install
~ yarn dev

Added an example request to the method

# /api/hello

async function handler(req, res) {
  const data = await fetch( "https://reqres.in/api/users/2");
  const result = await data.json();
  res.status(200).json({ id: result.data });
}
export default handler;

Started sending requests with autocannon

first run (~500 connection) same errors https://github.com/vercel/next.js/issues/53837

~ autocannon -c 10 -d 5 -p 10 http://127.0.0.1:3000/api/hello

-> 509 2xx responses, 120 non 2xx responses

error Error: Ensure bailed, found path does not match ensure type (pages/app)
    at ensurePageImpl (/nextjs-v13.4.16-fetch-failed/.yarn/__virtual__/next-virtual-f3349ac7a2/0/cache/next-npm-13.4.16-744eec6b7d-b9e3460619.zip/node_modules/next/dist/server/dev/on-demand-entry-handler.js:483:23) {
  digest: undefined
}

second run (~1000 connection)

~ autocannon -c 100 -d 5 -p 10 http://127.0.0.1:3000/api/hello

-> 667 2xx responses, 321 non 2xx responses

error TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11576:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
thien-do commented 1 year ago

In my case this happened when the server's content type header is not what actually is. For example the content type says it's gzip but the content is without compression, thus causing the decompression failed.

To exclude/verify if this is your case, you can add this header temporarily and try again:

"Accept-Encoding": "identity",
raflymln commented 1 year ago

In my case this happened when the server's content type header is not what actually is. For example the content type says it's gzip but the content is without compression, thus causing the decompression failed.

To exclude/verify if this is your case, you can add this header temporarily and try again:

"Accept-Encoding": "identity",

Thank you for this fix, you helped me so much 🙏