Error maximum call stack size exceeded npm

I'm trying to run npm install, this is output from console: npm ERR! Linux 4.8.0-27-generic npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "install" npm ERR! node v6.9.1 npm ERR! npm v3.10.8 npm...

I’m trying to run npm install, this is output from console:

npm ERR! Linux 4.8.0-27-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "install"
npm ERR! node v6.9.1
npm ERR! npm  v3.10.8

npm ERR! Maximum call stack size exceeded
npm ERR! 
npm ERR! If you need help, you may report this error at:
npm ERR!     <https://github.com/npm/npm/issues>

and this is content of npm-debug.log:

113791 verbose stack RangeError: Maximum call stack size exceeded
113791 verbose stack     at Object.color (/usr/lib/node_modules/npm/node_modules/npmlog/node_modules/console-control-strings/index.js:115:32)
113791 verbose stack     at EventEmitter.log._format (/usr/lib/node_modules/npm/node_modules/npmlog/log.js:252:51)
113791 verbose stack     at EventEmitter.<anonymous> (/usr/lib/node_modules/npm/node_modules/npmlog/log.js:138:24)
113791 verbose stack     at emitThree (events.js:116:13)
113791 verbose stack     at emit (events.js:194:7)
113791 verbose stack     at .<anonymous> (/usr/lib/node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet/tracker-group.js:23:18)
113791 verbose stack     at emitThree (events.js:116:13)
113791 verbose stack     at emit (events.js:194:7)
113791 verbose stack     at .<anonymous> (/usr/lib/node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet/tracker-group.js:23:18)
113791 verbose stack     at emitThree (events.js:116:13)
113791 verbose stack     at emit (events.js:194:7)
113792 verbose cwd /home/giorgi/AdMove/dev/web-advertiser-admove
113793 error Linux 4.8.0-27-generic
113794 error argv "/usr/bin/nodejs" "/usr/bin/npm" "install"
113795 error node v6.9.1
113796 error npm  v3.10.8
113797 error Maximum call stack size exceeded
113798 error If you need help, you may report this error at:
113798 error     <https://github.com/npm/npm/issues>
113799 verbose exit [ 1, true ]

Removed node_modules several times and tried to reinstall. Can’t understand what’s the reason that causes this and how to fix it.

asked Nov 12, 2016 at 18:41

GROX13's user avatar

GROX13GROX13

4,4554 gold badges23 silver badges39 bronze badges

6

metzelder’s answer helped me fix the issue. however if you run the command npm cache clean, it will give you a message

As of npm@5, the npm cache self-heals from corruption issues and data extracted from the cache is guaranteed to be valid

So, as of npm5 you can do by adding a --force flag to the command.

So the command is:

npm cache clean --force

G-Ram's user avatar

G-Ram

334 silver badges6 bronze badges

answered Jul 14, 2018 at 8:06

codingbruh's user avatar

codingbruhcodingbruh

2,2131 gold badge11 silver badges14 bronze badges

10

npm rebuild
it has solved my problem

João Marcos Gris's user avatar

answered Nov 7, 2018 at 6:51

YYY's user avatar

YYYYYY

3,3805 gold badges19 silver badges23 bronze badges

6

Try removing package-lock.json and the node_modules folder:

rm package-lock.json
rm -r node_modules

bobbyz's user avatar

bobbyz

4,8783 gold badges30 silver badges42 bronze badges

answered Apr 6, 2019 at 17:37

Марат Зимнуров's user avatar

7

I had the same issue with npm install.
After a lot of search, I found out that removing your .npmrc file or its content (found at %USERPROFILE%/.npmrc), will solve this issue. This worked for me.

Rene Knop's user avatar

Rene Knop

1,7383 gold badges14 silver badges27 bronze badges

answered Nov 19, 2018 at 19:37

Arwa S k's user avatar

Arwa S kArwa S k

2963 silver badges7 bronze badges

1

npm uninstall

npm cache clean --force

I tried these two methods but they didn’t work. After, I deleted the node_modules directory and ran npm install again, it still didn’t work. Lastly, I deleted package-lock.json and created a new package-lock.json file using

npm install

Michael Mior's user avatar

Michael Mior

27.7k8 gold badges88 silver badges112 bronze badges

answered Feb 18, 2019 at 11:24

Kerim Kuşcu's user avatar

Kerim KuşcuKerim Kuşcu

4074 silver badges12 bronze badges

4

I have overcome this issue by doing following:

  • Delete all the content of the npm dependencies. You can find the default install location according to this thread:
    https://stackoverflow.com/a/5926706/1850297

  • Before you run npm install command, I suggest to run npm cache clean --force

Kesav Sundar M's user avatar

answered Apr 10, 2018 at 9:45

metzelder's user avatar

metzeldermetzelder

6262 gold badges15 silver badges33 bronze badges

1

npm rebuild will work for sure

answered Oct 12, 2019 at 3:38

Gopi P's user avatar

Gopi PGopi P

5089 silver badges19 bronze badges

4

In my case, update to the newest version:

npm install -g npm

answered Aug 15, 2019 at 14:41

AvantContra's user avatar

AvantContraAvantContra

3611 gold badge3 silver badges10 bronze badges

I deleted

node_modules

and then reinstalled by

npm install

It worked for me

answered Oct 27, 2018 at 15:00

Umair Khalid's user avatar

Umair KhalidUmair Khalid

2,1791 gold badge19 silver badges28 bronze badges

3

I have also faced the same problem and this is how i resolved it.

  1. First of all you need to make sure that your node and npm versions are up to date. if not please upgrade your node and npm packages to latest versions.

    nvm install 12.18.3 // update node version through node version manager
    
    npm install npm // update your npm version to latest
    
  2. Delete your node_modules folder and package-lock.json file.

  3. Force clean the entire NPM cache by using following comand.

    npm cache clean --force
    
  4. Re-Install all the dependencies.

    npm install
    
  5. If above step didn’t resolve your problem, try to re-install your dependencies after executing following command.

    npm rebuild
    

answered Aug 3, 2020 at 16:37

Aravinda Meewalaarachchi's user avatar

1

This issue can also happen if you’re trying to install a package that doesn’t exist or if you’re trying to install a version that doesn’t exist.

answered Dec 26, 2019 at 13:57

Melchia's user avatar

MelchiaMelchia

21.5k21 gold badges97 silver badges113 bronze badges

2

npm cache clean returns below message

As of npm@5, the npm cache self-heals from corruption issues and data extracted from the cache is guaranteed to be valid. If you want to make sure everything is consistent, use ‘npm cache verify’ instead. On the other hand, if you’re debugging an issue with the installer, you can use npm install --cache /tmp/empty-cache to use a temporary cache instead of nuking the actual one.

If you run npm cache verify, as specified above, then it actually runs cache verification and garbage collection which fixes the problem.

Cache verified and compressed (~AppDataRoamingnpm-cache_cacache):
Content verified: 6183 (447214684 bytes) Content garbage-collected: 16
(653745 bytes) Index entries: 9633

MetaSean's user avatar

MetaSean

76115 silver badges24 bronze badges

answered Mar 18, 2019 at 13:01

Synster's user avatar

SynsterSynster

3298 silver badges15 bronze badges

1

Happened in docker (node:15-buster) for me.

Remember to use WORKDIR /<folder> so that it doesn’t conflict with original npm libraries installed.

The folder can be anything but system folders, so that includes using /.

answered Oct 30, 2020 at 8:29

danieltan95's user avatar

danieltan95danieltan95

7646 silver badges12 bronze badges

3

In case none of these answer work for you, it may be because the terminal you’re using isn’t the right one/ your node_modules is used by another part of your computer.

In my case I kept juggling between this error (maximum call stack size exceeded) and the access error event when I did a sudo npm i.

The fix was to close my IDE (which was WebStorm), run npm i in a basic terminal, and that was it.

Michael Mior's user avatar

Michael Mior

27.7k8 gold badges88 silver badges112 bronze badges

answered May 14, 2019 at 10:33

Jonathan Simonney's user avatar

1

I’m not a Windows user, so if you are, try to check Rene Knop comment.

For Unix/OSX users, I’ve removed the root .npmrc file ~/.npmrc.
Before you’re going to try it, please,
check if there is nothing necessary over there
you can use this command to bring all content into your terminal: cat ~/.npmrc .

If you have got something like:

cat: /Users/$USER/.npmrc: No such file or directory

to save a copy:

cp ~/.npmrc ~/.npmrc_copy

Now, try to remove it (Works for bash users: Unix / Ubuntu / OSX …):

rm -f ~/.npmrc

This worked for me.
Hope this will be helpful for others.

answered Apr 11, 2019 at 14:17

naorz's user avatar

naorznaorz

3493 silver badges6 bronze badges

In my case I had a custom .npmrc file that included an auth token for authenticating with a private npm registry.

The token had expired, which helpfully returned code E401: Incorrect or missing password locally, but ERR! Maximum call stack size exceeded from the CI build.

answered Aug 25, 2021 at 12:18

wolfyuk's user avatar

wolfyukwolfyuk

7441 gold badge8 silver badges24 bronze badges

You uninstall npm package and force clean the cache and close terminal and reinstall whichever package be.

$sudo npm uninstall <package - name>
$sudo npm cache clean --force

Then restart terminal and check

Still not working upgrade both npm and node to the latest version

answered Feb 17, 2019 at 7:53

Gajendra K S's user avatar

Today we encountered this error when running an npm prune even after running an npm cache clean --force.

Versions:

node 13.8.0 
npm 6.13.6

Deleting the package-lock.json worked for this case as well. Thank you all!

answered Apr 8, 2020 at 14:38

Jeff Hampton's user avatar

In general, once a module has been installed, it’s much more convenient to use npm ci instead of npm install. Please check out this SO answer for the advantages of the former with respect to the later in a production environment.
So please just run

npm ci

All dependencies will be updated, and the problem will disappear. Or it will error in the case there’s some grave de-synchronization between one and the other.

answered Nov 2, 2020 at 11:18

jjmerelo's user avatar

jjmerelojjmerelo

21.9k7 gold badges37 silver badges83 bronze badges

Most of the times, this issue occurs if you are using the system provided by the organization you work for and it’s vpn restricts the use of this command.
In this case, you may try to disconnect from organization vpn and then execute this command.

answered Mar 17, 2021 at 12:03

jaihind's user avatar

jaihindjaihind

1,0721 gold badge8 silver badges9 bronze badges

I tried everything to fix this issue on my Mac. I think the issue started when I had already downloaded npm from Node.js and then reinstalled it with Homebrew while following along with a Team Treehouse video.

Here’s what I tried:

From https://docs.npmjs.com/misc/removing-npm

sudo npm uninstall npm -g
sudo make uninstall
sudo rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/npm*

From How do I completely uninstall Node.js, and reinstall from beginning (Mac OS X)

sudo rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/{npm*,node*,man1/node*}

Here’s what worked:

In the end, the only thing that worked for me was to clone down the npm-reinstall repo from GitHub that completely removed everything related to npm on my Mac.

https://github.com/brock/node-reinstall

I then had to reinstall node and npm from Node.js.

answered Nov 6, 2018 at 13:33

Caleb Spindler's user avatar

0

I tried everything to fix this issue on my windows 7 machine like

Reinstalling and rebuilding npm

At last, I fixed this small configuration setting issue by wasting my entire day.

How I resolved this issue

Removing my project specific configurations in global .npmrc
at location like drive:/Windows/Users/../.npmrc

answered May 16, 2019 at 10:42

Rajashekhar Reddy's user avatar

I solved it 100% I had this problem with gulp version: 3.5.6.

You should clean the package-lock.js and then run npm install and It worked form

answered Nov 1, 2019 at 12:47

Hidayat Arghandabi's user avatar

Our company dev environment uses Artifactory as the default registry for our NPM dependencies, and when running npm install it was defaulting to this, which did not work… so manually specifying the main npm registry via npm install --registry https://registry.npmjs.org fixed this issue for me…

answered Jan 7, 2020 at 16:18

Joshua Barker's user avatar

Joshua BarkerJoshua Barker

9072 gold badges10 silver badges22 bronze badges

I was facing the same error, I was trying to install jest into to one of the packages in a monorepo project.

If you are using Yarn + Learna to package a monorepo project, you will have to navigate to the package.json inside the target package and then run npm install or npm install <package name>.

answered Jun 10, 2020 at 3:58

Shrivathsa's user avatar

I don’t know why, but I ran npm install with sudo and it worked.

sudo npm install

answered Sep 27, 2021 at 15:41

Spixz's user avatar

SpixzSpixz

311 silver badge7 bronze badges

I had this problem and it was due to an upgrade of my git executable. I rolled back to Git-2.21.0.rc1.windows.1-64-bit and added this to my environment path and it fixed my issue.

answered Feb 15, 2019 at 23:09

Finchy70's user avatar

Finchy70Finchy70

4219 silver badges24 bronze badges

The one thing that finally worked for me on Mac was upgrading from node 8.12 to 10.x using NVM.

I uninstalled all other versions of Node with NVM, then installed 10.x, then ran nvm alias default node, which tells NVM to always default to the latest available node version on a shell.

After that, my live reloading issue went away!

answered Jul 30, 2019 at 18:12

bildungsroman's user avatar

bildungsromanbildungsroman

3651 gold badge8 silver badges17 bronze badges

Switching to yarn solved the issue for me.

answered Oct 17, 2019 at 20:33

vgaltes's user avatar

vgaltesvgaltes

1,14011 silver badges17 bronze badges

Sometimes, you may see the npm maximum call stack size exceeded error when you run the npm install command:

npm ERR! Maximum call stack size exceeded

The detail of the error may vary inside your npm-debug.log file, but this error is commonly caused by npm unable to complete a process related to your npm install command.

For example, if you’re updating a package version, then npm may not be able to delete the old files inside your node_modules folder and replace it with the new ones.

The exact cause of the error may vary depending on what packages you are installing, but you can use the following steps to try and fix the error:

Installing the latest NodeJS and npm version

First, make sure that you are using the latest NodeJS and npm versions for your project.

Now the npm install command sometimes builds native addons for NodeJS which compiles a native program written in C or C++ and uses it as a part of your Node package.

When you update your NodeJS and npm to the latest version, the compiled native addons inside your node_modules/ folder must be rebuild using the latest npm version for it to work.

If you don’t want to run npm install every time you change the NodeJS version, then I recommend you to use Node Version Manager to install multiple NodeJS versions on your local computer.

Once you installed the latest NodeJS and npm software, then delete your node_modules folder and package-lock.json file:

rm -rf node_modules && rm package-lock.json

Once both are removed, then clean your npm cache using the following command:

Finally, try installing your dependencies again:

You should be able to install all dependencies without the maximum call stack size exceeded error now.

Sometimes, there’s another error that may appear when you run the npm install command.

You may get a JavaScript heap out of memory error, or there’s npm code 1 error.

I hope these tutorials have helped you to debug npm installation issues. 🙏

I’m opening this issue because:

  • npm is crashing.
  • npm is producing an incorrect install.
  • npm is doing something I don’t understand.
  • Other (see below for feature requests):

What’s going wrong?

npm install any-module-name-here fails with «Maximum call stack size exceeded».

I’m using npm@5 in various projects already, but it fails to install / update in a project where I have local symlinks in the tree. At least, that is the only difference I can tell so far.

How can the CLI team reproduce the problem?

I can’t share the repo, but I managed to fix the issues with two small hacks:

First npm crashed with «Maximum call stack size exceeded» and this log:

0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/Cellar/node@6/6.10.2/bin/node',
1 verbose cli   '/usr/local/bin/npm',
1 verbose cli   'install',
1 verbose cli   '@studio/backend' ]
2 info using npm@5.0.3
3 info using node@v6.10.2
4 verbose npm-session 3581873a35a3b427
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 http fetch GET 304 https://registry.npmjs.org/@studio%2fbackend 761ms (from cache)
8 silly pacote range manifest for @studio/backend@^1.6.0 fetched in 783ms
9 verbose stack RangeError: Maximum call stack size exceeded
9 verbose stack     at /usr/local/lib/node_modules/npm/lib/install/node.js:33:42
9 verbose stack     at Array.forEach (native)
9 verbose stack     at exports.create (/usr/local/lib/node_modules/npm/lib/install/node.js:33:25)
9 verbose stack     at /usr/local/lib/node_modules/npm/lib/install/node.js:36:14
9 verbose stack     at Array.forEach (native)
9 verbose stack     at exports.create (/usr/local/lib/node_modules/npm/lib/install/node.js:33:25)
9 verbose stack     at normalizeTree (/usr/local/lib/node_modules/npm/lib/install.js:377:5)
9 verbose stack     at Array.forEach (native)
9 verbose stack     at normalizeTree (/usr/local/lib/node_modules/npm/lib/install.js:379:19)
9 verbose stack     at Array.forEach (native)
9 verbose stack     at normalizeTree (/usr/local/lib/node_modules/npm/lib/install.js:379:19)
9 verbose stack     at Array.forEach (native)
9 verbose stack     at normalizeTree (/usr/local/lib/node_modules/npm/lib/install.js:379:19)
9 verbose stack     at Array.forEach (native)
9 verbose stack     at normalizeTree (/usr/local/lib/node_modules/npm/lib/install.js:379:19)
9 verbose stack     at Array.forEach (native)
10 verbose cwd /Users/max/projects/studio-analyzer
11 verbose Darwin 16.5.0
12 verbose argv "/usr/local/Cellar/node@6/6.10.2/bin/node" "/usr/local/bin/npm" "install" "@studio/backend"
13 verbose node v6.10.2
14 verbose npm  v5.0.3
15 error Maximum call stack size exceeded
16 verbose exit [ 1, true ]

So I went into /usr/local/lib/node_modules/npm/lib/install.js and changed normalizeTree to this:

  function normalizeTree (tree, seen = new Set()) {
    if (seen.has(tree)) {
      return;
    }
    seen.add(tree);
    createNode(tree)
    tree.location = flatNameFromTree(tree)
    tree.children.forEach((child) => normalizeTree(child, seen))
  }

Secondly, npm install that-module failed with «Cannot read property ‘type’ of undefined» and this log:

0 info it worked if it ends with ok
1 verbose cli [ '/usr/local/Cellar/node@6/6.10.2/bin/node',
1 verbose cli   '/usr/local/bin/npm',
1 verbose cli   'i',
1 verbose cli   '@studio/backend' ]
2 info using npm@5.0.3
3 info using node@v6.10.2
4 verbose npm-session 9f7ff18ce9a433f1

# heaps of logs with the ideal tree and detail about all my private modules

558 verbose stack TypeError: Cannot read property 'type' of undefined
558 verbose stack     at /usr/local/lib/node_modules/npm/lib/shrinkwrap.js:111:12
558 verbose stack     at Array.forEach (native)
558 verbose stack     at shrinkwrapDeps (/usr/local/lib/node_modules/npm/lib/shrinkwrap.js:103:97)
558 verbose stack     at /usr/local/lib/node_modules/npm/lib/shrinkwrap.js:138:7
558 verbose stack     at Array.forEach (native)
558 verbose stack     at shrinkwrapDeps (/usr/local/lib/node_modules/npm/lib/shrinkwrap.js:103:97)
558 verbose stack     at treeToShrinkwrap (/usr/local/lib/node_modules/npm/lib/shrinkwrap.js:93:5)
558 verbose stack     at /usr/local/lib/node_modules/npm/lib/shrinkwrap.js:76:21
558 verbose stack     at done (/usr/local/lib/node_modules/npm/lib/utils/lifecycle.js:136:5)
558 verbose stack     at LOOP (/usr/local/lib/node_modules/npm/node_modules/slide/lib/chain.js:7:26)
558 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/slide/lib/chain.js:18:7
558 verbose stack     at /usr/local/lib/node_modules/npm/lib/utils/lifecycle.js:333:20
558 verbose stack     at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/polyfills.js:284:29
558 verbose stack     at FSReqWrap.oncomplete (fs.js:123:15)
559 verbose cwd /Users/max/projects/studio-analyzer
560 verbose Darwin 16.5.0
561 verbose argv "/usr/local/Cellar/node@6/6.10.2/bin/node" "/usr/local/bin/npm" "i" "@studio/backend"
562 verbose node v6.10.2
563 verbose npm  v5.0.3
564 error Cannot read property 'type' of undefined
565 verbose exit [ 1, true ]

This was also easy to fix in /usr/local/lib/node_modules/npm/lib/shrinkwrap.js. Basically getRequested(child) may return undefined, so I added this below line 110:

… and 🎉 npm install that-module worked again.

Hope this helps fixing those issue.

supporting information:

  • npm -v prints: 5.0.3
  • node -v prints: v6.10.2
  • npm config get registry prints: https://registry.npmjs.org/
  • Windows, OS X/macOS, or Linux?: macOS
  • Network issues:
    • Geographic location where npm was run:
    • I use a proxy to connect to the npm registry.
    • I use a proxy to connect to the web.
    • I use a proxy when downloading Git repos.
    • I access the npm registry via a VPN
    • I don’t use a proxy, but have limited or unreliable internet access.
  • Container:
    • I develop using Vagrant on Windows.
    • I develop using Vagrant on OS X or Linux.
    • I develop / deploy using Docker.
    • I deploy to a PaaS (Triton, Heroku).

Ситуация: заказчик попросил разместить на странице кликабельную картинку, а чтобы на неё обратило внимание больше посетителей, попросил сделать вокруг неё моргающую рамку. Логика моргания в скрипте очень простая:

  1. В первой функции находим на странице нужный элемент.
  2. Добавляем рамку с какой-то задержкой (чтобы она какое-то время была на экране).
  3. Вызываем функцию убирания рамки.
  4. Внутри второй функции находим тот же элемент на странице.
  5. Убираем рамку с задержкой.
  6. Вызываем первую функцию добавления рамки.

Код простой, поэтому делаем всё в одном файле:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Pulse</title>
	<style type="text/css">
	/*	рамка, которая будет моргать	*/
		.pulse { box-shadow: 0px 0px 4px 4px #AEA79F; }
	</style>
</head>
<body>
	<div id="pulseDiv"> 
    	<a href="#">
      		<div id="advisersDiv">
        		<img src="https://thecode.media/wp-content/uploads/2020/08/photo_2020-08-05-12.04.57.jpeg">
        	</div>
      	</a>
</div>
<!-- подключаем jQuery -->
<script src="https://yastatic.net/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
<!-- наш скрипт -->
<script type="text/javascript">
	// добавляем рамку
	function fadeIn() {
		// находим нужный элемент и добавляем рамку с задержкой
  	$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
  	// затем убираем рамку
  	fadeOut();
	};
	// убираем рамку
	function fadeOut() {
		// находим нужный элемент и убираем рамку с задержкой
   	$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
   	// затем добавляем 
   	fadeIn();
	};
	// запускаем моргание рамки
	fadeIn();
</script>

</body>
</html>

Но при открытии страницы в браузере мы видим, что ничего не моргает, а в консоли появилась ошибка:

❌ Uncaught RangeError: Maximum call stack size exceeded

Что это значит: в браузере произошло переполнение стека вызовов и из-за этого он не может больше выполнять этот скрипт.

Переполнения стека простыми словами означает вот что:

  1. Когда компьютер что-то делает, он это делает последовательно — 1, 2, 3, 4.
  2. Иногда ему нужно отвлечься от одного и сходить сделать что-то другое — а, б, в, г, д. Получается что-то вроде 1, 2, 3 → а, б, в, г, д → 4.
  3. Вот эти переходы 3 → а и д → 4 — это компьютеру нужно запомнить, что он выполнял пункт 3, и потом к нему вернуться.
  4. Каждое запоминание, что компьютер бросил и куда ему нужно вернуться, — это называется «вызов».
  5. Вызовы хранятся в стеке вызовов. Это стопка таких ссылок типа «когда закончишь вот это, вернись туда».
  6. Стек не резиновый и может переполняться.

Что делать с ошибкой Uncaught RangeError: Maximum call stack size exceeded

Эта ошибка — классическая ошибка переполнения стека во время выполнения рекурсивных функций.

Рекурсия — это когда мы вызываем функцию внутри самой себя, но чуть с другими параметрами. Когда параметр дойдёт до конечного значения, цепочка разматывается обратно и функция собирает вместе все значения. Это удобно, когда у нас есть чёткий алгоритм подсчёта с понятными правилами вычислений.

В нашем случае рекурсия возникает, когда в конце обеих функций мы вызываем другую: 

  1. Функции начинают бесконтрольно вызывать себя бесконечное число раз.
  2. Стек вызовов начинает запоминать вызов каждой функции, чтобы, когда она закончится, вернуться к тому, что было раньше.
  3. Стек — это определённая область памяти, у которой есть свой объём.
  4. Вызовы не заканчиваются, и стек переполняется — в него больше нельзя записать вызов новой функции, чтобы потом вернуться обратно.
  5. Браузер видит всё это безобразие и останавливает скрипт.

То же самое будет, если мы попробуем запустить простую рекурсию слишком много раз:

Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded

Как исправить ошибку Uncaught RangeError: Maximum call stack size exceeded

Самый простой способ исправить эту ошибку — контролировать количество рекурсивных вызовов, например проверять это значение на входе. Если это невозможно, то стоит подумать, как можно переделать алгоритм, чтобы обойтись без рекурсии.

В нашем случае проблема возникает из-за того, что мы вызывали вторые функции бесконтрольно, поэтому они множились без ограничений. Решение — ограничить вызов функции одной секундой — так они будут убираться из стека и переполнения не произойдёт:

<script type="text/javascript">
// добавляем рамку
function fadeIn() {
	// находим нужный элемент и добавляем рамку с задержкой
	$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
	// через секунду убираем рамку
	setTimeout(fadeOut,1000)
};
// убираем рамку
function fadeOut() {
	// находим нужный элемент и убираем рамку с задержкой
 	$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
 	// через секунду добавляем рамку
	setTimeout(fadeIn,1000)
};
// запускаем моргание рамки
fadeIn();
</script>

Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded

Вёрстка:

Кирилл Климентьев

Привет, Хабровчане!

Большинство разработчиков, которые использовали рекурсию для решения своих задач, видели такую ошибку:

 RangeError: Maximum call stack size exceeded. 

Но не каждый разработчик задумывался о том, а что означает «размер стэка вызовов» и каков же этот размер? А в чем его измерять?

Думаю, те, кто работают с языками, напрямую работающими с памятью, смогут легко ответить на этот вопрос, а вот типичный фронтэнд разработчик скорее всего задает себе подобные вопросы впервые. Что-ж, попробуем разобраться!

Многие полагают, что браузер ограничивает нас именно в количестве вызовов, но это не так. В данной статье я покажу на простых примерах, как это работает на самом деле.

О чем ты вообще, автор?

Для статьи важно понимание таких понятий как Execution Stack, Execution Context. Если вы не знаете, что это такое, то советую об этом почитать. На данном ресурсе уже было достаточно хороших статей на эту тему. Пример — https://habr.com/ru/company/ruvds/blog/422089/

Когда возникает эта ошибка?

Разберем на простом примере — функция, которая рекурсивно вызывает сама себя.

const func = () => {
    func();
}

Если попытаться вызвать такую функцию, то мы увидим в консоли/терминале ошибку, о которой я упомянул выше.

А что если подглядеть, сколько же раз выполнилась функция перед тем, как возникла ошибка?

На данном этапе код запускается в Chrome DevTools последней версии на март 2021. Результат будет различаться в разных браузерах. В дальнейшем в статье я упомяну об этом.

Для эксперимента будем использовать вот такой код:

let i = 0;

const func = () => {
  i++;

  func();
};

try {
  func();
} catch (e) {
  // Словили ошибку переполнения стэка и вывели значение счетчика в консоль
  console.log(i);
}

Результатом вывода в консоль стало число в 13914. Делаем вывод, что перед тем, как переполнить стэк, наша функция вызвалась почти 14 тысяч раз.

Магия начинается тогда, когда мы начинаем играться с этим кодом. Допустим, изменим его вот таким образом:

let i = 0;

const func = () => {
  let someVariable = i + 1;
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}

Единственное, что мы добавили, это объявление переменной someVariable в теле функции. Казалось бы, ничего не поменялось, но число стало меньше. На этот раз функция выполнилась 12523 раз. Что более чем на тысячу меньше, чем в прошлом примере. Чтобы убедиться, что это не погрешность, пробуем выполнять такой код несколько раз, но видим одни и те же результаты в консоли.

Почему же так? Что изменилось? Как понять, посмотрев на функцию, сколько раз она может выполниться рекурсивно?!

Магия раскрыта

Отличие второго примера от первого — наличие дополнительной переменной внутри тела функции. На этом все. Соответственно, можно догадаться, именно из-за этого максимальное количество рекурсивных вызовов стало меньше. Что-ж, а что, если у нас будет не одна, а четыре переменных внутри функции? По этой логике, количество рекурсивных вызовов станет еще меньше? Проверим: 

let i = 0;

const func = () => {
  let a = i + 1;
  let b = a + 1;
  let c = b + 1;
  let d = c + 1;
  let e = d + 1;
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}

По этой логике, значение счетчика должно стать еще меньше. Выдыхая, видим вывод — 8945. Ага, оно стало еще меньше. Значит, мы на правильном пути. Хочу привести небольшую аналогию, чтобы даже самым маленьким стало понятно.

Execution Stack (Call Stack) — это емкость с водой. Изначально она пустая. Так получилось, что эта емкость с водой стоит прямо на электрической проводке. Как только емкость переполнится, вода проливается на провода, и мы видим ошибку в консоли. При каждом новом рекурсивном вызове функции в стэк падает капелька воды. Само собой, чем капелька воды крупнее, тем быстрее наполнится стэк.

Емкости бывают разные по размеру. И размер емкости в данном примере — это размер коллстэка. А точнее — количество байт, которое он максимально может в себе удержать. Как гласит статья про Call Stack (Execution Stack), которую я приложил в начале, на каждый вызов функции создается Execution Context — контекст вызова функции (не путать с this). И упрощая, в нем, помимо разных «подкапотных» штук, содержатся все переменные, которые мы объявили внутри функции. Как Execution Context, так и каждая переменная внутри него имеют определенный размер, который они занимают в памяти. Сложив эти два размера мы и получим «размер» капли, которая капает в кувшин при каждом рекурсивном вызове функции.

У нас уже достаточно много данных. Может быть, поэкспериментируем еще? А давайте попробуем вычислить, какой размер коллстэка в движке, который использует Chrome?

Математика все-таки пригодилась

Как мы выяснили, у нас есть две неизвестные, которые составляют размер функции (капельки, которая падает в емкость). Это размер самого Execution Stack, а так же сумма размеров всех переменных внутри функции. Назовем первую N, а вторую K. Сам же неизвестный размер коллстэка обозначим как X.

В итоге — количество байт, которое занимает функция (в упрощенном виде) будет:

FunctionSize = N + K * SizeOfVar

SizeOfVar в данном случае — количество байт, которые занимает переменная в памяти.

Учитывая, что мы знаем количество вызовов первой функции, в теле которой не объявляются переменные, размер коллстэка можно выразить как:

X = (N + 0 *  SizeOfVar)* 13914 = N * 13914

И, для второго случая, возьмем функцию, внутри которой было объявлено пять переменных.

X = (N + 5 * SizeOfVar) * 8945

Иксы в обоих случаях обозначают одно и то же число — размер коллстэка. Как учили в школе, можем приравнять правые части уравнений.

N * 13914 = (N + 5 * SizeOfVar) * 8945

Выглядит неплохо. У нас тут две неизвестные переменные — N и SizeOfVar. Если N мы не можем откуда-то узнать, то что насчет SizeOfVar? Заметим, что во всех функциях, которые фигурировали выше, переменные хранили значение с типом «number», а значит, нужно просто узнать, сколько же байт в памяти занимает одна такая переменная.

С помощью великого гугла получаем ответ — «Числа в JavaScript представлены 64-битными значениями с плавающей запятой. В байте 8 бит, в результате каждое число занимает 64/8 = 8 байт.» Вот она — последняя неизвестная. 8 байт. Подставляем ее в наше уравнение и считаем, чем равно N.

N * 13914 = (N + 5 * 8) * 8945

Упрощаем:

N * 13914 = N * 8945 + 40 * 8945

Если выразить отсюда N, то получим ответ: N равно приблизительно 72. В данном случае 72 байтам.

Теперь, подставив N = 72 в самое первое уравнение, получим, что размер коллстэка в Chrome равен… 1002128 байтов. Это почти один мегабайт. Не так уж и много, согласитесь.

Мы получили какое-то число, но как убедиться, что наши расчеты верны и число правильное? А давайте попробуем с помощью этого числа спрогнозировать, сколько раз сможет выполниться функция, внутри которой будет объявлено 7 переменных типа ‘number’. 

Считаем: Ага, каждая функция будет занимать (72 + 7 * 8) байт, это 128. Разделим 1002128 на 128 и получим число… 7829! Согласно нашим расчетам, такая функция сможет рекурсивно вызваться именно 7829 раз! Идем проверять это в реальном бою…

Мы были очень даже близки. Реальное число отличается от теоретического всего на 3. Я считаю, что это успех. В наших расчетах было несколько округлений, поэтому результат мы посчитали не идеально, но, очень-очень близко. Небольшая погрешность в таком деле — нормально.

Получается, что мы посчитали все верно и можем утверждать, что размер пустого ExecutionStack в Chrome равен 72 байтам, а размер коллстэка — чуть меньше одного мегабайта.

Отличная работа!

Важное примечание

Размер стэка разнится от браузера к браузеру. Возьмем простейшую функцию из начала статьи. Выполнив ее в Сафари получим совершенно другую цифру. Целых 45606 вызовов. Функция с пятью переменными внутри выполнилась бы 39905 раз. В NodeJS числа очень близки к Chrome по понятным причинам. Любопытный читатель может проверить это самостоятельно на своем любимом движке JavaScript. 

А что с непримитивами?

Если с числами все вроде бы понятно, то что насчет типа данных Object? 

let i = 0;

const func = () => {
  const a = {
    key: i + 1,
  };
  i++;

  func();
};

try {
  func();
} catch (e) {
  console.log(i);
}

Простейший пример на ваших глазах. Такая функция сможет рекурсивно вызваться 12516. Это практически столько же, сколько и функция с одной переменной внутри. Тут в дело вступает механизм хранения и передачи объектов в JS’е — по ссылке. Думаю, большинство уже знают об этом.

А что с этим? А как поведет себя вот это? А что с *?

Как вы заметили, экспериментировать можно бесконечно. Можно придумать огромное количество кейсов, которые будут прояснять эту ситуацию глубже и глубже. Можно ставить эксперименты при разных условиях, в разных браузерах, на разных движках. Оставляю это на тех, кого эта тема заинтересовала.

Итоги:

  • Количество рекурсивных вызовов функции до переполнения стэка зависит от самих функций.

  • Размер стэка измеряется в байтах.

  • Чем «тяжелее» функция, тем меньше раз она может быть вызвана рекурсивно.

  • Размер стэка в разных движках различается.

Вопрос особо любознательным: А сколько переменных типа «number» должно быть объявлено в функции, чтобы она могла выполниться рекурсивно всего два раза, после чего стэк переполнится?

The JavaScript RangeError: Maximum call stack size exceeded is an error that occurs when there are too many function calls, or if a function is missing a base case.

Error message:

RangeError: Maximum call stack size exceeded

Error Type:

RangeError

What Causes RangeError: Maximum Call Stack Size Exceeded

The RangeError: Maximum call stack size exceeded is thrown when a function call is made that exceeds the call stack size. This can occur due to the following reasons:

  • Too many function calls.
  • Issues in handling recursion, e.g. missing base case in a recursive function to stop calling itself infinitely.
  • Out of range operations.

RangeError: Maximum Call Stack Size Exceeded Example

Here’s an example of a JavaScript RangeError: Maximum call stack size exceeded thrown when using a recursive function that does not have a base case:

function myFunc() {
    myFunc();
}

myFunc();

Since the recursive function myFunc() does not have a terminating condition (base case), calling it creates an infinite loop as the function keeps calling itself over and over again until the RangeError: Maximum call stack size exceeded error occurs:

Uncaught RangeError: Maximum call stack size exceeded
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)
    at myFunc (test.js:2:2)

How to Avoid RangeError: Maximum Call Stack Size Exceeded

If this error is encountered when calling recursive functions, it should be ensured that the function has a defined base case to terminate the recursive calls.

In case this error occurs due to an excessive number of function calls or variables, these should be reduced as much as possible. Any out of range operations should also be checked and avoided. These issues can be inspected using the browser console and developer tools.

The earlier example can be updated to include a base case:

function myFunc(i) {
    if (i >= 5) {
        return;
    }
    myFunc(i+1);
}

myFunc(1);

The above code avoids the error since recursive calls terminate when the base case is met.

Track, Analyze and Manage Errors With Rollbar

Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing JavaScript errors easier than ever. Sign Up Today!

Понравилась статья? Поделить с друзьями:
  • Error max search depth too small
  • Error max number of partition
  • Error matrix index out of range maple
  • Error material sprites bubble proxy animatedtexture not found
  • Error matdatepicker no provider found for dateadapter