{"record":{"id":"212a52cc7621e50f","repo":"puppetlabs/puppet","slug":"operator-operator-is-not-implemented","errorCode":null,"errorMessage":"Operator '#{operator}' is not implemented","messagePattern":"Operator '#(.+?)' is not implemented","errorType":"validation","errorClass":"Puppet::Util::Package::Version::Range::ValidationFailure","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/package/version/range.rb","lineNumber":51,"sourceCode":"      raise ValidationFailure, \"Unable to parse '#{range_string}' as a string\" unless range_string.is_a?(String)\n\n      simples = range_string.split(RANGE_SPLIT).map do |simple|\n        match, operator, version = *simple.match(FULL_REGEX)\n        raise ValidationFailure, \"Unable to parse '#{simple}' as a version range identifier\" unless match\n\n        case operator\n        when '>'\n          Gt.new(version_class.parse(version))\n        when '>='\n          GtEq.new(version_class.parse(version))\n        when '<'\n          Lt.new(version_class.parse(version))\n        when '<='\n          LtEq.new(version_class.parse(version))\n        when ''\n          Eq.new(version_class.parse(version))\n        else\n          raise ValidationFailure, \"Operator '#{operator}' is not implemented\"\n        end\n      end\n      simples.size == 1 ? simples[0] : MinMax.new(simples[0], simples[1])\n    end\n  end\nend\n","sourceCodeStart":33,"sourceCodeEnd":58,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/package/version/range.rb#L33-L58","documentation":"The operator dispatch in Range.parse (range.rb:51): FULL_REGEX happily captures ANY run of [<>=] characters as the 'operator', but the case statement only implements '>', '>=', '<', '<=' and '' (empty = exact equality). Any other captured operator falls to else and raises ValidationFailure 'Operator ... is not implemented'.","triggerScenarios":"Range.parse('==1.0', klass) (pip/gem equality syntax -> operator '=='), Range.parse('=1.0', klass) (single '=' is a captured operator, NOT the empty/Equality case -> raise), Range.parse('=>1.0', klass), Range.parse('<>1.0', klass), Range.parse('>>1', klass).","commonSituations":"Constraints copied from requirements.txt ('==1.26.0') or Gemfile ('= 1.0'); npm-style '^1.2.3' would instead fail the FULL_REGEX match (caret is captured by (.+) as part of the version and then fails version_class.parse); users assuming '=' means pinned.","solutions":["For exact pins, drop the operator entirely: Range.parse('1.2.3', klass) maps to Eq.","Translate equality syntax before parsing: replace '==' or '=' at token start with ''.","Whitelist-validate tokens: /\\A(?:>=|<=|>|<)?[^<>=]+\\Z/ before handing to parse.","Rescue Range::ValidationFailure and surface a message listing supported operators > >= < <= and bare version."],"exampleFix":"// before\nrng = Puppet::Util::Package::Version::Range.parse(ensure_spec, klass) # ensure_spec = '==1.26.0'\n\n// after\nspec = ensure_spec.strip.gsub(/\\A==?/, '')\nrng = Puppet::Util::Package::Version::Range.parse(spec, klass) # '1.26.0' -> Eq","handlingStrategy":"validation","validationCode":"SUPPORTED = /\\A(?:>=|<=|>|<)?(?!=)[^<>=]+\\z/\nreturn :invalid unless constraint.match?(SUPPORTED)","typeGuard":null,"tryCatchPattern":"begin\n  Range.parse(constraint, version_class)\nrescue Puppet::Util::Package::Version::Range::ValidationFailure => e\n  raise e if e.message.include?('not implemented')\n  raise\nend","preventionTips":["Translate '=='/'=' pins to a bare version before Range.parse.","Whitelist the operator vocabulary at the input boundary and reject anything else with a clear message."],"tags":["puppet","version-range","package-version","operator","validation"],"backgroundTag":"version-range-parse-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}