Skip to content

json 3.0.0 breaks Puppet::Util::Json and the test suite #654

Description

@miharp

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:

  1. Puppet::Util::Json.load passes an options hash positionally to ::JSON.parse(string, options). This now raises ArgumentError: 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 are undefined method 'fetch' for nil from metadata loads returning nil).
  2. Puppet::Util::Json.dump references ::JSON::PRETTY_STATE_PROTOTYPE, which was removed. This surfaces as NameError: uninitialized constant JSON::PRETTY_STATE_PROTOTYPE from puppet facts show.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions