When I tried to deploy my Rails app to Heroku recently, I ran into a weird and frustrating error involving Heroku automatically adding x86_64-linux
, which then led to a Node.js version mismatch and broke my asset precompilation step.
If you’re using Webpack or node sass in a Rails project and pushing to Heroku, you might hit the same problem. Here’s the story of how I identified, debugged, and fixed the issue and how you can too.
The Code That Trigger the Error
My project was pretty standard a Rails 6 app with some Webpack integration for styling. Here’s what my setup looked like.
package.json
{
"name": "my-heroku-app",
"version": "1.0.0",
"scripts": {
"build": "webpack --mode production"
},
"dependencies": {
"node-sass": "^4.14.1"
}
}
Gemfile
ruby '2.7.4'
gem 'rails', '~> 6.1.7'
gem 'sassc-rails'
.node-version
and .ruby-version
# .node-version
14.15.5
# .ruby-version
2.7.4
Procfile
web: bundle exec puma -C config/puma.rb
The Problem
Even though I had clearly set Node 14.15.5 in .node-version
, Heroku didn’t respect that by default. Instead, I saw this during deployment:
remote: -----> Installing node-v16.13.1-linux-x64
And then, boom the dreaded error during asset compilation:
error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
This came from node-gyp
, which is used to compile native bindings for node-sass
. The C++ standard used by Node 16 was more strict, and that caused the error.
What Actually Cause It
Here’s the breakdown:
- Heroku installs Node 16.13.1 by default, unless you tell it otherwise.
node-sass@4.14.1
doesn’t support Node 16 it supports up to Node 14.- The native bindings in
node-sass
failed to compile under Node 16. - That broke the asset pipeline, and the deployment failed.
The Fix
Specify Node and Yarn Versions in package.json
To make Heroku use the right versions, I added this:
"engines": {
"node": "14.15.5",
"yarn": "1.22.17"
}
This fixed the Heroku Node version mismatch.
Pin the Correct Buildpacks
I explicitly set the buildpacks via CLI:
heroku buildpacks:set heroku/nodejs
heroku buildpacks:add heroku/ruby
This ensures Node is installed before Ruby, which is necessary if you use Webpack or node-sass in your Rails project.
Replace node-sass
with sass
(Dart Sass)
Since node-sass
is deprecated and uses native bindings (which is always fragile on Heroku), I just decided to move on:
npm uninstall node-sass
npm install sass
Dart Sass is written in JavaScript and doesn’t require compilation, so it’s much safer for deployment environments like Heroku.
Clean Node Modules and Cache
After making changes, I cleared everything to avoid leftover issues:
rm -rf node_modules
rm -rf yarn.lock package-lock.json
yarn install
Then I committed everything and redeployed:
git add .
git commit -m "Fix Heroku deploy: set node version and switch to sass"
git push heroku main
Add Environment Logging
To make sure I knew exactly what Heroku was using during build, I added a simple logging script:
log-env.js
console.log("Node Version:", process.version);
console.log("Platform:", process.platform);
console.log("Arch:", process.arch);
And updated the scripts
in package.json
:
"scripts": {
"env-check": "node log-env.js",
"build": "npm run env-check && webpack --mode production"
}
Add Node Version Check for Safety
I also added a version check script to prevent accidental installs on unsupported Node versions:
check-node-version.js
const [major] = process.versions.node.split('.').map(Number);
if (major > 14) {
console.error(" Node version too high for node-sass 4.14.1");
process.exit(1);
}
And in package.json
:
"scripts": {
"postinstall": "node check-node-version.js"
}
This saved me from future surprises if I ever reinstalled dependencies.
Summary
Step | Action |
---|---|
Set Node/Yarn | Use "engines" in package.json |
Fix Buildpacks | Ensure NodeJS buildpack is before Ruby |
Migrate | Replace node-sass with sass |
Clean Cache | Clear node_modules and lockfiles |
Add Logging | Track versions in build with log-env.js |
Add Safety | Warn if Node version is too new |
Final Thought
This whole issue was a great reminder that deployment environments don’t always match your local setup. Even when I had.node-version
set correctly, Heroku ignored it and the node-sass
version mismatch led to some deep C++ errors that seemed unrelated at first.