{"record":{"id":"e789b52c42be210c","repo":"puppetlabs/puppet","slug":"cannot-compare-this-array-with-other-ot","errorCode":null,"errorMessage":"Cannot compare #{this} (Array) with #{other} (#{other.class}). Only ±Float::INFINITY accepted.","messagePattern":"Cannot compare #(.+?) \\(Array\\) with #(.+?) \\(#(.+?)\\)\\. Only ±Float::INFINITY accepted\\.","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/package/version/pip.rb","lineNumber":156,"sourceCode":"      if !local\n        local_key = [[-Float::INFINITY, \"\"]]\n      else\n        local_key = local.map { |i| (i.is_a? Integer) ? [i, \"\"] : [-Float::INFINITY, i] }\n      end\n\n      [epoch, release_key, pre_key, post_key, dev_key, local_key]\n    end\n\n    def compare(this, other)\n      if (this.is_a? Array) && (other.is_a? Array)\n        this  << -Float::INFINITY if this.length < other.length\n        other << -Float::INFINITY if this.length > other.length\n\n        this.each_with_index do |element, index|\n          return compare(element, other.at(index)) if element != other.at(index)\n        end\n      elsif (this.is_a? Array) && !(other.is_a? Array)\n        raise Puppet::Error, \"Cannot compare #{this} (Array) with #{other} (#{other.class}). Only ±Float::INFINITY accepted.\" unless other.abs == Float::INFINITY\n\n        return other == -Float::INFINITY ? 1 : -1\n      elsif !(this.is_a? Array) && (other.is_a? Array)\n        raise Puppet::Error, \"Cannot compare #{this} (#{this.class}) with #{other} (Array). Only ±Float::INFINITY accepted.\" unless this.abs == Float::INFINITY\n\n        return this == -Float::INFINITY ? -1 : 1\n      end\n      this <=> other\n    end\n\n    class ValidationFailure < ArgumentError\n      def initialize(version)\n        super(\"#{version} is not a valid python package version. Please refer to https://www.python.org/dev/peps/pep-0440/.\")\n      end\n    end\n  end\nend\n","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/package/version/pip.rb#L138-L174","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Only ever obtain Pip instances from Puppet::Util::Package::Version::Pip.parse; never build or mutate @key/@release_data manually.","Clear/refetch cached version objects after upgrading puppet so keys are rebuilt by the current code.","Replace test doubles with real parsed instances (Pip.parse('1.0.0rc1') etc.).","Wrap risky comparisons in rescue Puppet::Error and re-parse both operands once before giving up."],"exampleFix":"// before\ndef compare_versions(a, b)\n  a <=> b # a.key was hand-built and now holds a finite Integer where b has an Array\nend\n\n// after\ndef compare_versions(a, b)\n  a = Puppet::Util::Package::Version::Pip.parse(a.to_s)\n  b = Puppet::Util::Package::Version::Pip.parse(b.to_s)\n  a <=> b\nend","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"PIP = Puppet::Util::Package::Version::Pip\ndef safely_comparable?(a, b)\n  a.is_a?(PIP) && b.is_a?(PIP) && !a.instance_variable_get(:@key).nil? && !b.instance_variable_get(:@key).nil?\nend","tryCatchPattern":"begin\n  a <=> b\nrescue Puppet::Error => e\n  raise unless e.message.include?('Only ±Float::INFINITY')\n  a = PIP.parse(a.to_s); b = PIP.parse(b.to_s)\n  a <=> b\nend","preventionTips":["Only construct Pip versions via .parse; never assign or mutate key/instance data.","Use real parsed instances in tests instead of stubs with fabricated keys.","Include the puppet version in any cache key for parsed version objects so stale keys are never compared."],"tags":["pip","python","pep-440","version-comparison","invariant","internal-error"],"backgroundTag":"invalid-version-comparison","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}