Fix: Ruby Bundler Version Conflict — Gemfile Requirements Could Not Be Resolved
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix Ruby Bundler gem version conflicts — Gemfile.lock resolution, platform-specific gems, bundle update strategies, conflicting transitive dependencies, and Bundler version issues.
The Problem
Bundler fails to resolve gem dependencies:
Bundler could not find compatible versions for gem "activesupport":
In Gemfile:
rails (~> 7.1.0) was resolved to 7.1.3, which depends on
activesupport (= 7.1.3)
sidekiq (>= 7.0) was resolved to 7.2.0, which depends on
activesupport (>= 7.0, < 8.0)
some-gem (~> 3.0) was resolved to 3.0.1, which depends on
activesupport (< 7.0)Or bundle install fails after adding a new gem:
Could not find gem 'some-new-gem (~> 2.0)' in locally installed gems.
Run `bundle install` to install missing gems.Or the lockfile is out of sync on a different platform:
Your bundle only supports platforms ["x86_64-linux"] but your local platform
is aarch64-linux. Add the current platform to the lockfile with
`bundle lock --add-platform aarch64-linux` and try again.Or Bundler itself is the wrong version:
Bundler 2.3.0 is running, but your lockfile was generated with 2.5.0.
Installing Bundler 2.5.0 and restarting using that version.Why This Happens
Bundler resolves a set of gem versions that satisfies all constraints simultaneously. Conflicts arise when no single version of a shared dependency can satisfy the version ranges required by different gems.
The resolution process is deterministic but sensitive to the full dependency graph. Adding one gem can shift the entire solution space. For example, some-gem ~> 3.0 may require activesupport < 7.0, while Rails 7.1 pins activesupport = 7.1.3. No version of activesupport satisfies both, so Bundler gives up and prints the conflict chain. The error message is dense but precise — it tells you exactly which gems impose conflicting constraints and what versions were considered.
Platform and tooling differences make this worse. A lockfile generated on macOS with Apple Silicon (aarch64-darwin) may lack the platform entries needed for Linux CI runners (x86_64-linux). Gems with native extensions like nokogiri or grpc ship precompiled binaries per platform, and a missing platform entry forces Bundler to compile from source — which often fails in Docker Alpine containers because musl libc is incompatible with glibc-linked native code. And Bundler itself has evolved significantly: the resolver algorithm in Bundler 2.x is different from 1.x, and lockfiles generated with one major version may not resolve cleanly with the other.
Common causes:
- Transitive dependencies with incompatible version ranges — gem A requires
activesupport < 7.0while gem B requiresactivesupport >= 7.0 - Outdated
Gemfile.lock— the lockfile was generated on a different machine or with a different Bundler version - Platform-specific gems — gems with native extensions have platform-specific precompiled binaries. A lockfile generated on Linux may not have the macOS platform entry
- Bundler version mismatch — different Bundler versions have different resolver algorithms
- Overly strict version constraints — pinning gems to exact versions prevents Bundler from finding compatible combinations
Fix 1: Read the Conflict Error Carefully
The error message tells you exactly which gems conflict:
bundle install
# Read the full error — it shows the dependency chain:
# Bundler could not find compatible versions for gem "X":
# In Gemfile:
# gem_a requires X (~> 2.0)
# gem_b requires X (>= 3.0)
# No version of X satisfies both constraints
# Or use verbose output for more detail
bundle install --verboseIdentify the conflicting gem pair:
# Check what version of a specific gem is currently installed
bundle info activesupport
gem list activesupport
# Check a gem's dependencies
gem dependency some-gem --remote
# View the dependency graph
bundle viz # Requires graphviz — creates a dependency graph image
# Or text version:
bundle listFix 2: Update the Conflicting Gem
Try updating the specific gem that’s causing the conflict:
# Update a single gem and its dependencies
bundle update some-gem
# Update a gem without updating its dependencies (more conservative)
bundle update --conservative some-gem
# Update multiple gems at once
bundle update gem-a gem-b
# Check what would change before updating
bundle outdated
bundle outdated --strict # Only show gems with updates within version constraintsAfter updating, check if the conflict is resolved:
bundle install # Should succeed now
# Commit the updated Gemfile.lock
git add Gemfile.lock
git commit -m "Update Gemfile.lock after updating some-gem"Fix 3: Relax Version Constraints in Gemfile
Overly strict constraints cause unnecessary conflicts:
# Gemfile — common constraint mistakes and fixes
# WRONG — exact version pin prevents updates
gem 'rails', '7.0.4' # Only allows exactly 7.0.4
# BETTER — allow patch updates
gem 'rails', '~> 7.0.4' # Allows 7.0.x (x >= 4)
# BETTER — allow minor updates
gem 'rails', '~> 7.0' # Allows 7.x (x >= 0)
# WRONG — very old constraint blocks modern dependencies
gem 'some-gem', '~> 1.0' # When 2.0+ is required by other gems
# CORRECT — check the gem's changelog and update the constraint
gem 'some-gem', '~> 2.0'Use bundle exec to check if constraints work:
# Temporarily loosen a constraint to find a working version
# Then tighten it back after identifying the compatible range
# Check if removing version constraint resolves the conflict
# gem 'conflicting-gem' # Remove version spec temporarily
bundle install # Does it resolve?
bundle info conflicting-gem # Note the version it chose
# Then: gem 'conflicting-gem', '~> X.Y'Fix 4: Fix Platform-Specific Lockfile Issues
When working across different OS/CPU architectures:
# Check current platforms in Gemfile.lock
grep -A5 "PLATFORMS" Gemfile.lock
# Add missing platform
bundle lock --add-platform x86_64-linux
bundle lock --add-platform aarch64-linux # ARM Linux (M1/M2 Mac in Docker)
bundle lock --add-platform x86_64-darwin # Intel Mac
bundle lock --add-platform aarch64-darwin # Apple Silicon Mac
bundle lock --add-platform x86_64-mingw-ucrt # Windows
# Add all common platforms at once
bundle lock --add-platform \
x86_64-linux \
aarch64-linux \
x86_64-darwin \
aarch64-darwinAlpine Linux musl issues with native gems:
Alpine uses musl libc instead of glibc, and many native gem extensions are compiled against glibc. This affects nokogiri, grpc, pg, mysql2, and others:
# WRONG — nokogiri precompiled binary expects glibc
FROM ruby:3.3-alpine
RUN bundle install
# Error: nokogiri-1.16.0-x86_64-linux requires glibc
# FIX 1: Force compilation from source
RUN bundle config set force_ruby_platform true
RUN apk add --no-cache build-base libxml2-dev libxslt-dev
RUN bundle install
# FIX 2: Use the glibc-based image (simpler, larger image)
FROM ruby:3.3-slim
RUN bundle install # Precompiled binaries just work
# FIX 3: Add the musl platform to Gemfile.lock
bundle lock --add-platform x86_64-linux-muslConfigure Bundler to use platform-specific gems (nokogiri, grpc, etc.):
# Use precompiled platform gems instead of building from source
bundle config set force_ruby_platform false # Default — use precompiled
# For CI/production where native compilation is unavailable:
bundle config set force_ruby_platform true # Build from source alwaysFix 5: Fix Bundler Version Issues
Bundler 1.x and 2.x have different resolver behaviors. The BUNDLED WITH section at the bottom of Gemfile.lock records which Bundler version generated the lockfile.
# Check Gemfile.lock for required Bundler version
grep "BUNDLED WITH" Gemfile.lock
# BUNDLED WITH
# 2.5.0
# Check your installed Bundler version
bundler --version # or: bundle --version
# Install the required version
gem install bundler -v 2.5.0
# Run with a specific Bundler version
bundle _2.5.0_ install
# Update Bundler itself
gem update bundler
# Set Bundler version for the project
bundle config set --local bundler_version 2.5.0Bundler 1 vs 2 key differences:
| Behavior | Bundler 1.x | Bundler 2.x |
|---|---|---|
| Default source | RubyGems only | Warns if multiple sources |
| Platform detection | Basic | Native platform-specific gems |
BUNDLED WITH | Not enforced | Auto-installs correct version |
| Resolver | Greedy | Compact index, faster |
--deployment flag | Sets read-only mode | Deprecated (use bundle config set deployment true) |
If your CI runner has Bundler 1.x but the lockfile says BUNDLED WITH 2.5.0, install the correct version first:
# CI setup script
gem install bundler -v "$(grep -A1 'BUNDLED WITH' Gemfile.lock | tail -1 | tr -d ' ')"
bundle installFix 6: Ruby Version Manager Interactions
Each Ruby version manager stores gems and Bundler separately, and switching managers or Ruby versions can leave behind stale gem caches.
rbenv:
# After switching Ruby versions
rbenv install 3.3.0
rbenv local 3.3.0
gem install bundler
bundle install # Installs gems for the new Ruby version
# Clear gem cache if stale gems cause conflicts
rbenv rehash
gem pristine --allrvm:
# rvm uses gemsets — isolate gems per project
rvm install 3.3.0
rvm use 3.3.0
rvm gemset create myproject
rvm gemset use myproject
gem install bundler
bundle installasdf:
# asdf installs Ruby and Bundler separately
asdf install ruby 3.3.0
asdf local ruby 3.3.0
gem install bundler
asdf reshim ruby # Regenerate shims so 'bundle' points to new Ruby
bundle installchruby:
# chruby is lightweight — relies on ruby-install for compilation
ruby-install ruby 3.3.0
chruby ruby-3.3.0
gem install bundler
bundle installCommon mistake across all managers: after switching Ruby versions, the Gemfile.lock may reference gems compiled for the old Ruby ABI. Run bundle install to resolve native extensions for the current Ruby. If that fails, delete vendor/bundle (if using --path vendor/bundle) and re-install:
rm -rf vendor/bundle .bundle
bundle installFix 7: GitHub Actions ruby/setup-ruby
The ruby/setup-ruby action is the standard way to set up Ruby in CI. It handles Bundler installation, caching, and platform detection, but misconfiguration causes common conflicts:
# .github/workflows/test.yml
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true # Runs 'bundle install' and caches gems
# Common mistake: specifying a Bundler version that conflicts with Gemfile.lock
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler: '2.5.0' # Must match BUNDLED WITH in Gemfile.lock
bundler-cache: trueIf the CI lockfile goes out of sync:
# Fix: add all CI platforms to the lockfile locally
# then commit the updated Gemfile.lock
- name: Debug platform issue
run: |
ruby -e "puts RUBY_PLATFORM" # Shows the CI platform
grep -A5 PLATFORMS Gemfile.lock # Shows what the lockfile supports# On your local machine — add the CI runner platform
bundle lock --add-platform x86_64-linux
git add Gemfile.lock
git commit -m "Add x86_64-linux platform to Gemfile.lock"Fix 8: Nuclear Option — Regenerate the Lockfile
When the lockfile is badly out of sync, start fresh:
# CAUTION — this updates ALL gems to their latest compatible versions
# Make sure your tests pass after this
# Delete the lockfile and regenerate
rm Gemfile.lock
bundle install
# Or: update all gems at once (safer — keeps version constraints)
bundle update
# If specific gems should stay locked (e.g., Rails version)
# Make sure Gemfile specifies exact range:
# gem 'rails', '~> 7.1.0' # Only updates patch versions
bundle update # Updates everything else to latest compatible
# Run your test suite to catch regressions
rails test
# or: rspecCompare what changed:
# After regenerating, see what versions changed
git diff Gemfile.lock
# Review major version bumps that might need code changes
git diff Gemfile.lock | grep "^[+-]" | grep -v "^[+-][+-][+-]"Fix 9: Debug Dependency Resolution
When you can’t figure out why a gem is being pulled in:
# Find out why a gem is in your bundle
bundle info some-gem # Shows the gem and who requires it
# List all gems and their dependencies
bundle list --paths # Shows install paths
# Check if a gem is required directly or transitively
grep -r "some-gem" Gemfile Gemfile.lock
# Show the full dependency tree
bundle exec gem dependency --reverse-dependencies some-gem
# Check RubyGems.org for available versions
gem list some-gem --remote --all | head -20
# Find the highest version satisfying a constraint
gem list some-gem --remote | grep "^some-gem "When a gem requires an incompatible Ruby version:
# Error: gem-name requires Ruby version >= 3.0
# Check your Ruby version
ruby --version
# Switch Ruby version with rbenv
rbenv install 3.3.0
rbenv local 3.3.0 # Set for this directory
bundle install
# Or with rvm
rvm install 3.3.0
rvm use 3.3.0
bundle installUsing a private gem server:
# Gemfile — multiple gem sources
source 'https://rubygems.org'
# Private gem server (e.g., GitHub Packages, Gemfury, Artifactory)
source 'https://rubygems.pkg.github.com/your-org' do
gem 'private-gem', '~> 1.0'
end# Configure credentials for private server
bundle config set --local https://rubygems.pkg.github.com/your-org \
"username:ghp_yourtoken"
# Or set globally
bundle config set --global https://rubygems.pkg.github.com/your-org \
"username:ghp_yourtoken"Still Not Working?
Gems with the same name on different sources — if a gem exists on both RubyGems and a private server, Bundler may pick the wrong one. Use source blocks to be explicit about where each gem comes from.
bundle exec vs system commands — always run Ruby scripts and rake tasks with bundle exec to ensure the correct gem versions are used:
bundle exec rails server
bundle exec rspec
bundle exec rake db:migrate
# Without bundle exec — uses system gems, may conflictSpring and Bundler — if using Spring (Rails process preloader), changes to gems require restarting Spring: spring stop then bundle exec rails server. Spring caches the gem environment.
Gemfile.lock in .gitignore — the lockfile should always be committed for applications (not libraries). If it’s gitignored, every developer gets different gem versions, causing “works on my machine” bugs. Libraries (gems themselves) should NOT commit Gemfile.lock.
Docker multi-stage builds and gem cache — if you copy gems from a builder stage, ensure both stages use the same platform. A common mistake is building gems in a ruby:3.3 (Debian) stage and copying them into a ruby:3.3-alpine (musl) stage. The native extensions compiled against glibc will segfault or fail to load on Alpine:
# WRONG — platform mismatch between stages
FROM ruby:3.3 AS builder
RUN bundle install
FROM ruby:3.3-alpine AS final
COPY --from=builder /usr/local/bundle /usr/local/bundle
# Native gems crash because they were compiled for glibc, not musl
# CORRECT — use the same base in both stages
FROM ruby:3.3-alpine AS builder
RUN apk add --no-cache build-base
RUN bundle install
FROM ruby:3.3-alpine AS final
COPY --from=builder /usr/local/bundle /usr/local/bundlerequired_ruby_version in gemspec blocking install — some gems specify a required_ruby_version that excludes your Ruby. Bundler shows this as a version conflict rather than a Ruby version error. Check gem specification some-gem required_ruby_version to see if your Ruby version is in the allowed range.
For related issues, see Fix: Rails N+1 Query Problem, Fix: Ruby LoadError Cannot Load Such File, Fix: Ruby NoMethodError, and Fix: pip No Matching Distribution.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Rails N+1 Query Problem — Too Many Database Queries
How to fix Rails N+1 queries — includes vs joins vs preload vs eager_load, Bullet gem detection, avoiding N+1 in serializers and views, and counter caches.
Fix: Docker Secrets Not Working — BuildKit --secret Not Mounting, Compose Secrets Undefined, or Secret Leaking into Image
How to fix Docker secrets — BuildKit secret mounts in Dockerfile, docker-compose secrets config, runtime vs build-time secrets, environment variable alternatives, and verifying secrets don't leak into image layers.
Fix: Python Packaging Not Working — Build Fails, Package Not Found After Install, or PyPI Upload Errors
How to fix Python packaging issues — pyproject.toml setup, build backends (setuptools/hatchling/flit), wheel vs sdist, editable installs, package discovery, and twine upload to PyPI.
Fix: AWS Lambda Layer Not Working — Module Not Found or Layer Not Applied
How to fix AWS Lambda Layer issues — directory structure, runtime compatibility, layer ARN configuration, dependency conflicts, size limits, and container image alternatives.