puppetlabs/puppet · error · Puppet::Error

Cannot compare #{this} (Array) with #{other} (#{other.class}

Error message

Cannot compare #{this} (Array) with #{other} (#{other.class}). Only ±Float::INFINITY accepted.

What it means

Internal invariant guard in Pip.compare (pip.rb:156), reached from Pip#<=>: when the left comparison key ('this') is an Array and the right ('other') is not, the only legal scalar is +Infinity/-Infinity, because #key uses those sentinels for absent pre/post/dev/local segments (see pip.rb:129-142). A finite scalar opposite an Array means the two keys were built inconsistently, and Puppet::Error is raised. Note a non-Numeric scalar would NoMethodError on .abs before this raise even fires.

Source

Thrown at lib/puppet/util/package/version/pip.rb:156

      if !local
        local_key = [[-Float::INFINITY, ""]]
      else
        local_key = local.map { |i| (i.is_a? Integer) ? [i, ""] : [-Float::INFINITY, i] }
      end

      [epoch, release_key, pre_key, post_key, dev_key, local_key]
    end

    def compare(this, other)
      if (this.is_a? Array) && (other.is_a? Array)
        this  << -Float::INFINITY if this.length < other.length
        other << -Float::INFINITY if this.length > other.length

        this.each_with_index do |element, index|
          return compare(element, other.at(index)) if element != other.at(index)
        end
      elsif (this.is_a? Array) && !(other.is_a? Array)
        raise Puppet::Error, "Cannot compare #{this} (Array) with #{other} (#{other.class}). Only ±Float::INFINITY accepted." unless other.abs == Float::INFINITY

        return other == -Float::INFINITY ? 1 : -1
      elsif !(this.is_a? Array) && (other.is_a? Array)
        raise Puppet::Error, "Cannot compare #{this} (#{this.class}) with #{other} (Array). Only ±Float::INFINITY accepted." unless this.abs == Float::INFINITY

        return this == -Float::INFINITY ? -1 : 1
      end
      this <=> other
    end

    class ValidationFailure < ArgumentError
      def initialize(version)
        super("#{version} is not a valid python package version. Please refer to https://www.python.org/dev/peps/pep-0440/.")
      end
    end
  end
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Only ever obtain Pip instances from Puppet::Util::Package::Version::Pip.parse; never build or mutate @key/@release_data manually.
  2. Clear/refetch cached version objects after upgrading puppet so keys are rebuilt by the current code.
  3. Replace test doubles with real parsed instances (Pip.parse('1.0.0rc1') etc.).
  4. Wrap risky comparisons in rescue Puppet::Error and re-parse both operands once before giving up.

Example fix

// before
def compare_versions(a, b)
  a <=> b # a.key was hand-built and now holds a finite Integer where b has an Array
end

// after
def compare_versions(a, b)
  a = Puppet::Util::Package::Version::Pip.parse(a.to_s)
  b = Puppet::Util::Package::Version::Pip.parse(b.to_s)
  a <=> b
end
Defensive patterns

Strategy: type-guard

Type guard

PIP = Puppet::Util::Package::Version::Pip
def safely_comparable?(a, b)
  a.is_a?(PIP) && b.is_a?(PIP) && !a.instance_variable_get(:@key).nil? && !b.instance_variable_get(:@key).nil?
end

Try / catch

begin
  a <=> b
rescue Puppet::Error => e
  raise unless e.message.include?('Only ±Float::INFINITY')
  a = PIP.parse(a.to_s); b = PIP.parse(b.to_s)
  a <=> b
end

Prevention

When it happens

Trigger: Comparing Pip instances whose @key arrays were mutated or hand-built (dup + modify, subclass overriding #key); comparing a parsed version against a same-class object constructed via Pip.new/send bypassing parse; release_key (an Array of Integers, pip.rb:126) meeting a finite Integer at the same slot.

Common situations: Test doubles/stubs of the Pip class that fabricate key data; monkey-patches or cache layers that store and reload partially-serialized version objects; library upgrades where #key changed shape but stale objects from a process-wide cache are still compared.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/e789b52c42be210c. Report an issue: GitHub.