Search code examples
reactjsreduxstack-overflowreact-reduxsetstate

Diagnosing RangeError: Maximum call stack size exceeded in React KeyEscapeUtils


Background

Our webapp is written with React and Redux using the official react-redux bindings. Another primary library used in this web app is PaperJS. We recently transitioned this to being a Redux app, though it has used React for a while.

The Problem

Refreshing sometimes (usually every other refresh) causes a

RangeError: Maximum call stack size exceeded
at String.replace (<anonymous>)
at Object.unescape (KeyEscapeUtils.js:49)
at flattenSingleChildIntoContext (flattenChildren.js:32)
at flattenChildren.js:53
at traverseAllChildrenImpl (traverseAllChildren.js:69)
at traverseAllChildrenImpl (traverseAllChildren.js:85)
at traverseAllChildren (traverseAllChildren.js:157)
at flattenChildren (flattenChildren.js:52)
at ReactDOMComponent._reconcilerUpdateChildren (ReactMultiChild.js:209)
at ReactDOMComponent._updateChildren (ReactMultiChild.js:315)

Here's the React source code where it's failing:

return ('' + keySubstring).replace(unescapeRegex, function (match) {
  return unescaperLookup[match];
});

and in context:

/**
 * Unescape and unwrap key for human-readable display
 *
 * @param {string} key to unescape.
 * @return {string} the unescaped key.
 */
function unescape(key) {
  var unescapeRegex = /(=0|=2)/g;
  var unescaperLookup = {
    '=0': '=',
    '=2': ':'
  };
  var keySubstring = key[0] === '.' && key[1] === '$' ? key.substring(2) : key.substring(1);

  return ('' + keySubstring).replace(unescapeRegex, function (match) {
    return unescaperLookup[match];
  });
}

This is probably indicative that somewhere I'm misusing React in my code, but since the stacktrace does not include references to any of my own code, I'm not sure what to look for. It seems to be an infinite loop of re-rendering, and I'm suspicious that it might be due to an improperly placed call to setState.

The Question

Is my suspicion likely? How can I further diagnose this issue, given that my own codebase is fairly extensive? What does it mean that this failed in KeyEscapeUtils?


Solution

  • I don't think the place that it failed is significant, since you seem to be caught in an infinite loop, and this just happens to be the spot that the call stack limit is exceeded.

    In order to diagnose, I would try turning on 'Pause on Exceptions' in chrome dev tools, if it's not already, and looking further up the stack trace for your own code when it pauses.

    You are correct that improper setState calls could be causing this. For instance, if you were calling setState unchecked in componentDidUpdate or render. It's curious though that it only happens sometimes.