assert_not magic?

Ryan Palo
        def test_code_isnt_magic
          code = [:ruby, :python, :javascript, :html, :css, :bash]
          assert_not code.any? { |language| language.magic? }
        end

        # A programming blog by Ryan Palo
        
Scroll down...

Solving an ExecJS Error that Breaks Jekyll on Rebuild

Jun 14, 2021 Buy me a coffee Buy me a coffee

Hi! I’m back. I was finishing up my Master’s program, slogging through the last 6 months of thesis coupled with about 9 months of extremely stressful work time that all adds up to a whole buttload of burnout. I’m real burnt out.

However, now that it’s over, things are improving. I opened a code editor today, and that’s a huge step. I have a couple of coding books on my holds list for our library. Things are starting to not seem like an insurmountable amount of effort anymore. We’re doing great.

“So, why not put myself back out there?” I thought to myself. I’ll just update my resume (🎉 I’m a Master of Computer Science now, after all! 🎉) and get things rebuilding again.

Bonk. Wrong. Error.

The fix was a little convoluted, so I thought I would write it up. TL;DR version: keep your crap updated. Broken xcode-select tools after a Mac OS upgrade led to un-updatable ruby versions, homebrew versions, and finally a Jekyll dependency I have.

Other takeaway: Ryan, just write your own static site generator in C with no dependencies, it’ll be fine.

Initial Investigation

I’ve got a weekly job that triggers a rebuild of my Netlify site just so I don’t have to remember to push everything all the time, and I can keep track of really huge supply chain changes. I had been seeing build errors for a couple of weeks (burnout, remember?) and apparently I was about to deal with them.

So, first things first: open up the repo, try a clean build, and see what happens. I deleted the Gemfile.lock and ran bundle to reinstall everything to see how that went and what got updated. This usually fixes most things.

Then I went to build the site:

bundle exec jekyll serve

This started well but dropped me with a 100% opaque error message:

                    ------------------------------------------------
      Jekyll 4.2.0   Please append `--trace` to the `serve` command 
                     for any additional information or backtrace. 
                    ------------------------------------------------

Great. Thank you so much.

bundle exec jekyll serve --trace

This error message was better:

bundler: failed to load command: jekyll (/Users/ryanpalo/.rbenv/versions/2.6.5/bin/jekyll)
ExecJS::ProgramError: TypeError: Cannot read property 'version' of undefined
  eval (eval at <anonymous> ((execjs):1:213), <anonymous>:1:10)
  (execjs):1:213
  (execjs):19:14
  (execjs):1:40
  Object.<anonymous> ((execjs):1:58)
  Module._compile (internal/modules/cjs/loader.js:1236:30)
  Object.Module._extensions..js (internal/modules/cjs/loader.js:1257:10)
  Module.load (internal/modules/cjs/loader.js:1085:32)
  Function.Module._load (internal/modules/cjs/loader.js:950:14)
  Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
  [...SNIP...]
  /Users/ryanpalo/.rbenv/versions/2.6.5/bin/jekyll:23:in `<top (required)>'

ExecJS was breaking something some kind of way.

ExecJS was broken?

After some searching around, I came upon this GitHub issue comment which I’ll copy the pertinent info from to save you a click:

This is related to using Ruby < 2.7. If you must stay on Ruby 2.6 or earlier, you probably need to stay on execjs < 2.8. The other option is to upgrade to Ruby 2.7 or above. Adding this here for posterity and anyone else running into that rough error message :)

Two solutions:

  1. Upgrade to Ruby 2.7 or later
  2. Downgrade to execjs 2.7 or earlier.

Out of Date Ruby

I looked up what the current stable Ruby version was and discovered I was behind by a whole minor version and more. Whoops. Time to upgrade to 2.7.3. I could and should probably upgrade to 3, but I can do that later after I get things unbroken.

My first step was to add that version to the versions available to rbenv.

$ rbenv install 2.7.3
ruby-build: definition not found: 2.7.3

See all available versions with `rbenv install --list'.

If the version you need is missing, try upgrading ruby-build:

  brew update && brew upgrade ruby-build

OK, my ruby-build database is out of date. That’s fair. Let’s get that updated.

Out of Date ruby-build

This one seemed easy enough: just follow the prompt:

$ brew update && brew upgrade ruby-build
Error: homebrew-cask is a shallow clone. To `brew update` first run:
  git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask" fetch --unshallow
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-cask. We don't do this for you automatically to avoid
repeatedly performing an expensive unshallow operation in CI systems (which
should instead be fixed to not use shallow clones). Sorry for the inconvenience!

Fart! OK, that’s fair. We can play by their rules.

Out of Date Homebrew (False rabbit hole, but still probably good to fix)

Once again, following the instructions:

git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask" fetch --unshallow

This updates Homebrew for me. Just for those of you glancing through quickly, this didn’t solve my overall problem, but it was probably healthy for my system overall.

Out of Date Command Line Tools??

After running the upgrade command again for ruby-build I hit another error message, which I probably could have spotted before:

Error: Your CLT does not support macOS 11.
It is either outdated or was modified.
Please update your CLT or delete it if no updates are available.
Update them from Software Update in System Preferences or run:
  softwareupdate --all --install --force

If that doesn't show you an update run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install

OK, not sure what a CLT is, but I vaguely remember YOLO upgrading a major version of Mac OS in the last couple of months. Thanks for that, past me. This StackExchange answer confirmed that could be my issue. Time to follow instructions again:

sudo rm -rf /Library/Developer/CommandLineTools
sudo xcode-select --install

I just about died as the installer estimated 8 hours to complete, but it completed in just about as long as it took me to get to this point in the writeup. Maybe 5 minutes–my laptop is a little old.

Back Up the Traceback Chain (Hopefully): Updating ruby-build

OK, we’re back on track.

brew upgrade

No error message, so far so good. Now to install the version of Ruby I need.

rbenv install 2.7.3

Bonk. No 2.7.3 version available. Crap. Double-check ruby-build is up-to-date: check. Well, let’s see what versions are available:

$ rbenv install --list
2.5.8
2.6.6
2.7.2
jruby-9.2.13.0
mruby-2.1.2
rbx-5.0
truffleruby-20.3.0
truffleruby+graalvm-20.3.0

OK, that’s weird that it doesn’t show the most recent, but let’s chalk it up to maybe the Homebrew package not having the latest yet. I checked the ruby-build repo and it shows 2.7.3 available, but, just to get things running, let’s just get what we can: 2.7.2.

rbenv install 2.7.2

See you in several hours…

Updating the Ruby Version in the Repo and Re-Installing Dependencies

OK! We’re back. The next step is to make sure Bundler is using the right version to do things. I’ve got a .ruby-version file in my repo. We’ll just update that to 2.7.2, delete the Gemfile.lock, and try re-installing all the dependencies.

bundle

Running the Build (Fingers Crossed)

Hope this works!

bundle exec jekyll serve

Son of a nutcracker! Same ExecJS error!

Pinning ExecJs to version 2.7

After returning to the ExecJS repo and reading further, apparently upgrading to Ruby 2.7 (or even 3.0) is a silver bullet. Multiple libraries including some JSON-parsing ones are tied into the same issue which apparently is a problem where they are trying to auto-detect versions of local programs using Node. I’ve got lots of thoughts on that for a Ruby library, but I’ll bottle them deep down inside for now. One user suggested just manually pinning ExecJS to 2.7 in your Gemfile. Here’s the commit. Sounds like as good a fix as any.

Update my Gemfile:

gem 'execjs', '2.7'       # Locking it due to an issue affecting node version checking

Delete the Gemfile.lock, run bundle to re-install, confirm version 2.7 has been installed, and rebuild again!

bundle exec jekyll serve

Success! Brilliant, brilliant success! And there you have it, my Monday morning rabbit hole. Thanks for reading! Hopefully more posts to come as I start feeling better.



Like my stuff? Have questions or feedback for me? Want to mentor me or get my help with something? Get in touch! To stay updated, subscribe via RSS