babel: BABEL_TRANSFORM_ERROR - babel traverse context - cannot read property "removeBinding" of null

Bug Report

EDIT by @nicolo-ribaudo

You can workaround this bug by making sure that @babel/core uses an older @babel/traverse version. If you are using yarn you can specify "@babel/traverse": "7.12.0" in resolutions, otherwise you can try downgrading it as described by https://github.com/babel/babel/issues/12383#issuecomment-732049261.


https://github.com/babel/babel/pull/12331 after this pr

“This is technically a breaking change (we are changing the default value of a parameter in the public API), but I couldn’t find anyone online using that parameter and I’m not sure why anyway would not wont it to use the correct context.”

is there anyone that do code review, here @babel ?

What do you think about semver?

image

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (10 by maintainers)

Most upvoted comments

I’ll open a PR today, hoping for a patch release today.

@w3nda You can try https://github.com/babel/babel/issues/12383#issuecomment-732049261, which is a generic workaround and not specific to babel-minify.

I think babel-plugin-minify-simplify is triggering this error (whether the fault is with the plugin or babel itself I don’t know). It can be seen when minifying bowser v1.9.4 for example.

To reproduce:

  1. Using node.js LTS v14.15.1 with npm version 6.14.8, set up a clean node project.
  2. Run npm install --save-dev @babel/cli @babel/core babel-preset-minify bowser@1.9.4
  3. Run npx babel --presets=babel-preset-minify node_modules/bowser/bowser.js

Released as 7.12.8

Right after https://github.com/babel/babel/pull/12390 and #12389 are merged, because they fix other regressions with this release.

Can the people who see this bug in their project try to replace the getSibling function in node_modules/@babel/core/node_modules/@babel/traverse/lib/path/family.js and/or node_modules/@babel/traverse/lib/path/family.js with this, and see if they still their build still crashes?

I confirm that patching getSibling in node_modules/@babel/core/node_modules/@babel/traverse/lib/path/family.js fixes the issue in my project.

With that change applied, the removeBinding errors are gone.

However I do still get the following error when minifying sortablejs@1.10.2 (also new with babel 7.12.7):

RangeError: node_modules/sortablejs/Sortable.js: Maximum call stack size exceeded
    at NodePath._resolve (node_modules/@babel/traverse/lib/path/introspection.js:310:18)
    at NodePath.resolve (node_modules/@babel/traverse/lib/path/introspection.js:307:15)
    at NodePath._resolve (node_modules/@babel/traverse/lib/path/introspection.js:317:31)
    at NodePath.resolve (node_modules/@babel/traverse/lib/path/introspection.js:307:15)
    at node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:72:27
    at Array.filter (<anonymous>)
    at getConstantViolationsBefore (node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:71:21)
    at getTypeAnnotationBindingConstantViolations (node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:36:28)
    at NodePath._default (node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:22:14)
    at NodePath._getTypeAnnotation (node_modules/@babel/traverse/lib/path/inference/index.js:59:20) {
  code: 'BABEL_TRANSFORM_ERROR'

I also got that error without the fix when disabling minify-simplify. I’m not sure the stack is entirely consistent; it might be hitting the limit at different points (or staying just beneath it in some cases) - without the fix but with minify-simplify disabled, I got the error while minifying d3@4.13.0:

RangeError: output/js/ext/full/d3.js: Maximum call stack size exceeded
    at NodePath.setScope (node_modules/@babel/traverse/lib/path/context.js:121:18)
    at NodePath.setContext (node_modules/@babel/traverse/lib/path/context.js:149:8)
    at NodePath._getKey (node_modules/@babel/traverse/lib/path/family.js:212:8)
    at NodePath.get (node_modules/@babel/traverse/lib/path/family.js:186:17)
    at NodePath._resolve (node_modules/@babel/traverse/lib/path/introspection.js:316:14)
    at NodePath.resolve (node_modules/@babel/traverse/lib/path/introspection.js:307:15)
    at node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:72:27
    at Array.filter (<anonymous>)
    at getConstantViolationsBefore (node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:71:21)
    at getTypeAnnotationBindingConstantViolations (node_modules/@babel/traverse/lib/path/inference/inferer-reference.js:36:28) {
  code: 'BABEL_TRANSFORM_ERROR'
}

Tested on Windows 10 x64.

I trimmed down the reproduction example to just two plugins: babel-plugin-transform-merge-sibling-variables and babel-plugin-minify-simplify. As an alternative to ["minify", { simplify: false }], a third workaround could be ["minify", { mergeVars: false }].

EDIT: In case someone is interested, this is the minimal amount of code to trigger the bug:

function compareVersions() {
  var precision = 0;
  var chunks = precision;
  while (precision) {}
}

and the problem uncovered by #12331 is that they try to do two different things with the chunks variable. transform-merge-sibling-vairables tries to generate

function compareVersions() {
  var precision = 0,
      chunks = precision;

  while (precision) {}
}

while minify-simplify tries to generate

function compareVersions() {
  var precision = 0;

  for (var chunks = precision; precision;);
}

Somehow one of them is getting a stale AST node causing problems (but this is not a bug with babel-minify, since @babel/traverse should prevent it).

A workaround that mostly worked for me was to disable the minify-simplify plugin by adding ["minify", { simplify: false }] to the preset options. Unfortunately I then got a “Maximum call stack size exceeded” error when minifying d3 v4.13.0 (but I haven’t investigated that yet).

The goal of #12331 was to fix problems really similar to the one reported in your stack trace.

Plugins can optimize AST traversal by passing a noScope: true option, which marks the internal scope tracker as not needed and sets the internal scope tracker to null.

The problem (fixed by #12331) was that sometimes an old value of noScope was used, and if a plugin run with noScope: true and then a different plugin run with noScope: false, the second one didn’t get a scope tracker instance causing errors such as Cannot read property removeBinding of null.

The “technically a breaking change” introduced by that PR is that now the noScope option is not ignored, so if a plugin sets noScope: true but then tries to use the scope tracker it will now throw an error (usually noScope: true was ignored before that PR). So the actual breaking change that I know of (and that I knew of when I wrote that description) is… respecting the value explicitly set by an option.

I’m thus surprised by this error, but yeah we should fix the regression.

However, we’ll need your help to do it. When opening a new issue in this repository, GitHub gives you a form similar to this one:

Schermata da 2020-11-23 02-21-57

As you can see, there are some predefined sections:

  • Current behavior: ✔️ (this is the stack trace you posted)
  • Input Code: ❌
  • Expected behavior: ✔️ (not crashing)
  • Babel Configuration: ❌

Without the missing information (marked with ❌), we cannot fix this issue.

  • If we just revert that PR, we don’t have any guarantee that it actually fixes the error.
  • If we are lucky and it fixes the error, we still cannot write a test for it. This makes it quite likely that we’ll break it again when fixing in another way the bug that #12331 was originally resolving.

I understand that depending on your employer’s policy it might be impossible for you to just give us the full contents of CustomDatePicker.js. You can comment out pieces of that file until the error goes away, and then just sharing the minimal portion of code needed to reproduce the crash.


PS. (I’m replying here to https://github.com/babel/babel/pull/12331#issuecomment-731854400)

You are breaking many production CI build

I strongly recommend using a lockfile package-lock.json or yarn.lock to avoid automatic dependencies upgrades. In this case your CI is failing, but in general “automatically downloading new code and executing it” is not a good idea from a security perspective.

@nicolo-ribaudo Are you serious? Have you understood that You have intentionally introduce a PR with a breaking change, without a major version, in a project used by 90% of the modern web? I do not think so.