Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"TypeError: handler is not a function at Server" deploying to Google Cloud Run #49338

Closed
1 task done
Sk92 opened this issue May 5, 2023 · 10 comments · Fixed by #49548
Closed
1 task done

"TypeError: handler is not a function at Server" deploying to Google Cloud Run #49338

Sk92 opened this issue May 5, 2023 · 10 comments · Fixed by #49548
Labels
bug Issue was opened via the bug report template. Output (export/standalone) Related to the the output option in `next.config.js`. Runtime Related to Node.js or Edge Runtime with Next.js.

Comments

@Sk92
Copy link

Sk92 commented May 5, 2023

Verify canary release

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

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:46 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6020
    Binaries:
      Node: 18.15.0
      npm: 9.5.0
      Yarn: 1.22.19
      pnpm: N/A
    Relevant packages:
      next: 13.4.1-canary.2
      eslint-config-next: N/A
      react: 18.2.0
      react-dom: 18.2.0

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

Middleware / Edge (API routes, runtime), Standalone mode (output: "standalone")

Link to the code that reproduces this issue

https://github.com/vercel/next.js/tree/canary/examples/with-docker

To Reproduce

  1. Clone the example repo with Docker
  2. Build the image using docker build -t eu.gcr.io/{PROJECT-ID}/nextjs-docker .
  3. Push the image to the Google Cloud Registry docker push eu.gcr.io/{PROJECT-ID}/nextjs-docker
  4. Go to Google Cloud Console > Cloud Run and create a new service using the image just pushed
  5. Wait for service creation, go to the URL, and you will get the "Internal Server Error".

Describe the Bug

Everytime Cloud Run service cold starts, you will get an "Internal Server Error".
This is the error printed in the logs:

TypeError: handler is not a function
at Server. (/app/server.js:29:11)
at Server.emit (node:events:513:28)
at parserOnIncoming (node:_http_server:1091:12)
at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17)

It looks like the server receives a request just before the handler is initialized with the function "createServerHandler".
If you refresh the page sometimes the error disappears and the page is shown correctly. This seems an error that occurs only when the service cold starts.

Expected Behavior

The page is shown without any error.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

@Sk92 Sk92 added the bug Issue was opened via the bug report template. label May 5, 2023
@github-actions github-actions bot added Runtime Related to Node.js or Edge Runtime with Next.js. Output (export/standalone) Related to the the output option in `next.config.js`. labels May 5, 2023
@adiron
Copy link

adiron commented May 6, 2023

I'm experimenting with Google Cloud Run for a Next.js deploy and I'm experiencing the same issue. Interestingly, it happens sporadically.

@adiron
Copy link

adiron commented May 6, 2023

I tried a lot of things. Eventually I downgraded to next 13.3.4. At this time I am no longer able to product this mysterious 500. I have also not been able to product this error locally.

@AliEskandari
Copy link

Running into the same issue. Gonna try changing min instances to 1 to reduce cold starts.

@espenbye
Copy link

espenbye commented May 8, 2023

Experiencing the same issue on AWS Amplify: aws-amplify/amplify-hosting#3466

@vamuscari
Copy link

I am also having this issue

@techiejd
Copy link

techiejd commented May 8, 2023

Same error on Google Cloud Run. I've downgraded to nextjs 13.3.4 as well and I haven't seen it again. Though, I am reticent to say it fixes it because it was so sporadic.

@vamuscari
Copy link

Okay, so I have a somewhat good idea of what's happening. When the docker container starts, the handler takes a few seconds to init. I don't know why it takes it that long, but it does. The option, for now, is to leave the minimum server instance at 1 to avoid cold stars.

To prove this, limit each container to a maximum number of 10 connections, then call the web page with a fetch of 10+ times. It fails when the tenth connection is hit, and a new container has to be spun up.

@adiron
Copy link

adiron commented May 9, 2023

Good find @vamuscari. Another solution might be to set a startup probe maybe? Worth a try

@ferdingler
Copy link
Contributor

PR with recommended fix: #49548

ijjk added a commit that referenced this issue May 11, 2023
…t handler is ready (#49548)

### Fixing a bug

Fixes #49536
Fixes #49338

### What?
Starting on next.js 13.4.0, the `server.js` file created by the
standalone output is incorrect because it does not wait until the Next
handler is ready before node http server starts accepting requests.

Initial requests will produce the following error:

```
TypeError: handler is not a function
at Server.<anonymous> (/tmp/app/server.js:29:11)
at Server.emit (node:events:513:28)
at parserOnIncoming (node:_http_server:998:12)
at HTTPParser.parserOnHeadersComplete (node:_http_common:128:17)
```

### Why?
The creation of the next server takes roughly 800ms on a basic hello
world app which causes the initial requests to fail because the
`handler` variable is not initialized.

### Solution
This changes the order of code so that Next Server is initialized before
the Node HTTP server and awaits until the promise is completed to kick
off the HTTP server.

### Alternative code

```js
let handler;

const server = http.createServer(async (req, res) => {
  try {
    await waitUntilHandlerIsReady(); // <---- wait here
    await handler(req, res);
  } catch (err) {
    console.error("Failed to call handler", err);
    res.statusCode = 500;
    res.end("Internal Server Error");
  }
});

async function waitUntilHandlerIsReady() {
  if (!handler) {
    await new Promise((resolve) => setTimeout(resolve, 200));
    await waitUntilHandlerIsReady();
  }
}
```

---------

Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. Output (export/standalone) Related to the the output option in `next.config.js`. Runtime Related to Node.js or Edge Runtime with Next.js.
Projects
None yet
7 participants