vercel / vercel/nft

`RangeError: Maximum call stack size exceeded` - For exports parsed into a lot of nodes

Open
#402 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
JavaScript
Stars
1.7k
Forks
185
PR merge metrics
No merged PRs in 30d

Description

TL;DR

Recursive call of walk in static-eval.ts for an export that is parsed into a lot of nodes leads to:

RangeError: Maximum call stack size exceeded

I am not sure whether this needs to be addressed as it is quite the edge case and probably very few cases will arise where something is exported that is leading to so many recursive calls and thus this error.

Background

I am deploying a Nuxt 3 Application to an arm64 server via a docker image, which worked fine until a couple of days ago when I was suddenly confronted with this error when making the production build
(more specifically when the build of Nuxt's Node.js server [nitro] was created).

RangeError: Maximum call stack size exceeded

Full Error Output
RangeError: Maximum call stack size exceeded

Exception in PromiseRejectCallback:
/app/node_modules/@vercel/nft/out/utils/static-eval.js:69
         let l = await walk(node.left);
                       ^

RangeError: Maximum call stack size exceeded


[nitro]  ERROR  RangeError: Maximum call stack size exceeded


undefined

at walk (node_modules/@vercel/nft/out/utils/static-eval.js:18:28)
at Object.BinaryExpression (node_modules/@vercel/nft/out/utils/static-eval.js:69:23)
at walk (node_modules/@vercel/nft/out/utils/static-eval.js:18:28)
at Object.BinaryExpression (node_modules/@vercel/nft/out/utils/static-eval.js:69:23)
at walk (node_modules/@vercel/nft/out/utils/static-eval.js:18:28)
at Object.BinaryExpression (node_modules/@vercel/nft/out/utils/static-eval.js:69:23)
at walk (node_modules/@vercel/nft/out/utils/static-eval.js:18:28)
at Object.BinaryExpression (node_modules/@vercel/nft/out/utils/static-eval.js:69:23)
at walk (node_modules/@vercel/nft/out/utils/static-eval.js:18:28)

Reason

After doing a little digging and debugging I found out the error occurred while evaluating the following export of mysql2

https://github.com/sidorares/node-mysql2/blob/a9c6c3eab0691ee03482514080d70d90344d0326/lib/constants/ssl_profiles.js

which was changed in https://github.com/sidorares/node-mysql2/pull/2131 and introduced a larger cert file wich is later parsed/traversed in https://github.com/vercel/nft/blob/main/src/utils/static-eval.ts .

They seem to have done a little oopsie when updating the certificates as it is a single big string (composed of a lot of concats)
inside an array instead of separating them one by one as array elements.

I guess it resolves all the concat operations for each node parsed from the single, large array element (so I think for each node the whole mash-up of certificate-string-concats is traversed with walk recursively or something similar like that) leading to the stack-size of 864 kBytes on arm64 machines being violated (as opposed to the stack size of 984 kBytes on amd64 machines where this error is not thrown)

Workaround

I downgraded to mysql2@3.9.2 for the time being.

It is also possible to change the stack-size via an --v8-optionsnode flag called --stack-size
and call e.g. yarn build like so:

node --stack-size=984 `$(which yarn) build`

as it is not possible to set it via the NODE_OPTIONS ENV Variable (not allowed by node)

Not sure what effects this could have in the long term as there seems to be good reason for the stack-size being smaller for arm64 machines.

Interesting read on this topic: https://github.com/nodejs/node/issues/41163

The recommended solution seems to be to rewrite recursive functions.

Steps to reproduce:

  1. npx nuxi@latest init [project-name]
  2. yarn add mysql2@3.9.3
  3. build application for production:
    run yarn install && yarn build on an arm64 machine
    or run docker build --platform linux/arm64 . with a Dockerfile like the following:
Dockerfile
FROM node:20.11-alpine as builder

WORKDIR /app
COPY package.json ./
COPY nuxt.config.ts ./
RUN yarn set version 1.22.19
RUN yarn config set network-timeout 600000 -g & yarn install
COPY . .
RUN yarn build

FROM node:20.11-alpine

COPY --from=builder /app/.output /test/.output

WORKDIR /test/.output

ENV NUXT_HOST=0.0.0.0
ENV NUXT_PORT=3000
EXPOSE 3000

CMD ["node", "/test/.output/server/index.mjs"]

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/utils/static-eval.ts and reproduce the failure using mysql2@3.9.3 in the provided Nuxt or arm64 Docker setup. Trace the recursive walk through the large concatenated export; done means the export no longer causes a maximum call stack error during dependency tracing.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.