Repository navigation
json 3.0.0 breaks Puppet::Util::Json and the test suite #654
Description
Summary
The json gem 3.0.0 was released on 2026-09-07. CI on every PR opened since then fails with about 1590 spec failures, for example the ruby 3.4 job on #653: https://github.com/OpenVoxProject/openvox/actions/runs/34143447163/job/101810265246. main passed the day before on the same base commit with json 2.x.
Why CI picks it up
Gemfile.lock is not tracked, and gem 'json' in the :packaging group of the Gemfile has no version constraint. The CI bundler-cache: true step installs all non-optional groups, so it resolves the newest json from rubygems, and that overrides the json default gem that ships with Ruby inside the test process. Dependabot is configured for bundler but can only bump constraints that exist in the Gemfile, so an unconstrained gem never gets a PR.
json is not a gemspec runtime dependency. Real installs use the json bundled with their Ruby, so this currently only affects CI. It will affect real installs once a Ruby release ships json 3 as its default gem.
What breaks
json 3.0.0 makes every option a keyword argument and removes several APIs. Three call sites in lib/puppet/util/json.rb are affected:
Puppet::Util::Json.loadpasses an options hash positionally to::JSON.parse(string, options). This now raisesArgumentError: wrong number of arguments (given 2, expected 1). Module metadata, catalogs, facts, and file metadata all go through this, so most of the failures cascade from it (994 of them areundefined method 'fetch' for nilfrom metadata loads returning nil).Puppet::Util::Json.dumpreferences::JSON::PRETTY_STATE_PROTOTYPE, which was removed. This surfaces asNameError: uninitialized constant JSON::PRETTY_STATE_PROTOTYPEfrompuppet facts show.- Two specs call
JSON.pretty_unparse, which was removed.
Also relevant from the changelog: allow_duplicate_key now defaults to false for both parsing and generating, and unknown options raise instead of being ignored. Both may surface once the above is fixed.
Proposed fix
Short term, to unblock CI and give Dependabot something to bump:
gem 'json', '< 3'in the :packaging group of the Gemfile.
Then port Puppet::Util::Json to the json 3 API in a way that still works with the json 2.x that ships with Ruby 3.2 through 4.0: pass options as keyword arguments to JSON.parse, and replace the PRETTY_STATE_PROTOTYPE merge with JSON.pretty_generate or the equivalent state options. Check the allow_duplicate_key default against any fixtures or wire formats that rely on the old behaviour.
Upstream puppetlabs/puppet has nothing on this yet.
Activity
Pin json below 3 to unblock CI
Pin json below 3 to unblock CI
Pin json below 3 until openvox supports it
Port Puppet::Util::Json to the json 3 API
Allow voxpupuli-test 15; pin json below 3 (6.3.0)
Port Puppet::Util::Json to the json 3 API
Smoke test the gem install against the newest json gem
Port Puppet::Util::Json to the json 3 API