ruby/rubygems · error · ProductionError

can't be updated because frozen mode is set If this is a de

Error message

can't be updated because frozen mode is set

If this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} freeze by running `#{suggested_command}`.

What it means

The companion frozen check in ensure_equivalent_gemfile_and_lockfile: a lockfile exists but lockfile_changes_summary reports drift between Gemfile and Gemfile.lock, so bundler raises ProductionError with the diff and, when the frozen setting came from local config rather than the environment, appends how to lift the freeze (lib/bundler/definition.rb:497). Under frozen mode the Gemfile is the contract and the lockfile must already satisfy it; this is bundler's equivalent of npm ci refusing an out-of-sync lockfile. It fires during install, Bundler.setup and inject.

Source

Thrown at lib/bundler/definition.rb:497

    end

    def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
      return unless Bundler.frozen_bundle?

      raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?

      msg = lockfile_changes_summary("frozen mode is set")
      return unless msg

      unless explicit_flag
        suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env)
          "bundle config set frozen false"
        end
        msg << "\n\nIf this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \
               "freeze by running `#{suggested_command}`." if suggested_command
      end

      raise ProductionError, msg
    end

    def validate_runtime!
      validate_ruby!
      validate_platforms!
    end

    def validate_ruby!
      return unless ruby_version

      if diff = ruby_version.diff(Bundler::RubyVersion.system)
        problem, expected, actual = diff

        msg = case problem
              when :engine
                "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}"
              when :version
                "Your Ruby version is #{actual}, but your Gemfile specified #{expected}"

View on GitHub (pinned to 86cbb817a3)

Solutions

  1. Regenerate the lockfile where writes are allowed: `bundle install`, commit Gemfile.lock, then retry the frozen environment
  2. If this machine may lock, unfreeze: `bundle config set frozen false` or unset BUNDLE_FROZEN
  3. Read the diff in the error, or run `bundle lock --check`, to see exactly which dependencies drifted
  4. Add `bundle lock --check` as a PR check so drift fails before deploy

Example fix

# before
# Gemfile: gem "sidekiq", "~> 7.0" changed to "~> 7.3" without re-locking
$ BUNDLE_FROZEN=true bundle install
# => can't be updated because frozen mode is set

# after
$ bundle install                      # dev machine re-locks
$ git commit -am "bump sidekiq and lockfile"
$ BUNDLE_FROZEN=true bundle install   # succeeds
Defensive patterns

Strategy: validation

Validate before calling

# pre-deploy gate
bundle lock --check || {
  echo "Gemfile and Gemfile.lock out of sync under frozen mode" >&2
  exit 1
}

Prevention

When it happens

Trigger: `bundle install` with BUNDLE_FROZEN=true after adding or changing a dependency in the Gemfile without re-locking; `bundle exec` or Bundler.setup under frozen with a stale lockfile; a PR edited the Gemfile but the deploy uses an old Gemfile.lock because only one of the two files was committed.

Common situations: Deploy pipelines with frozen enabled; `bundle config set frozen true` left over on a dev machine so every Gemfile edit fails the next install; BUNDLE_FROZEN baked into a base Docker image.

Related errors


AI-assisted analysis of ruby/rubygems@86cbb817a3 (2026-08-23). Data as JSON: /api/errors/0ef896b110812fcd. Report an issue: GitHub.