{"record":{"id":"23e935bd9dc6e422","repo":"puppetlabs/puppet","slug":"unable-to-parse-range-string-as-a-string","errorCode":null,"errorMessage":"Unable to parse '#{range_string}' as a string","messagePattern":"Unable to parse '#(.+?)' as a string","errorType":"validation","errorClass":"Puppet::Util::Package::Version::Range::ValidationFailure","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/package/version/range.rb","lineNumber":33,"sourceCode":"    # Currently parsed version range string may take any of the following\n    # forms:\n    #\n    # * Regular Version strings\n    #   * ex. `\"1.0.0\"`, `\"1.2.3-pre\"`\n    # * Inequalities\n    #   * ex. `\">1.0.0\"`, `\"<3.2.0\"`, `\">=4.0.0\"`\n    # * Range Intersections (min is always first)\n    #   * ex. `\">1.0.0 <=2.3.0\"`\n    #\n    RANGE_SPLIT = /\\s+/\n    FULL_REGEX = /\\A((?:[<>=])*)(.+)\\Z/\n\n    # @param range_string [String] the version range string to parse\n    # @param version_class [Version] a version class implementing comparison operators and parse method\n    # @return [Range] a new {Range} instance\n    # @api public\n    def self.parse(range_string, version_class)\n      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\"","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/package/version/range.rb#L15-L51","documentation":"Puppet::Util::Package::Version::Range.parse (range.rb:33) raises ValidationFailure unless range_string.is_a?(String). The parser then splits on whitespace and interprets each token as an optional operator (> >= < <=) plus a version, delegating version parsing to the supplied version_class (Debian/Gem/Pip).","triggerScenarios":"Range.parse(nil, Debian), Range.parse(['>1.0'], Gem) (array of tokens instead of joined string), Range.parse(range_object, version_class) (passing an already-parsed Gt/Eq instance back in), Range.parse(:'>=1.0', Pip) (symbol).","commonSituations":"nil default when a manifest parameter is unset; arrays from data bindings passed unjoined; round-tripping parsed ranges through code that expects raw strings.","solutions":["Join token arrays first: Range.parse(tokens.join(' '), version_class).","Check for nil/blank input before calling: return a default (e.g., Eq of the current version) when unset.","Type-guard with is_a?(String) and raise a descriptive error of your own naming the parameter.","Rescue Range::ValidationFailure (ArgumentError subclass) at input boundaries."],"exampleFix":"// before\nrng = Puppet::Util::Package::Version::Range.parse(params[:version_range], Debian) # nil\n\n// after\nraw = params[:version_range]\nrng = if raw.is_a?(String) && !raw.strip.empty?\n        Puppet::Util::Package::Version::Range.parse(raw, Debian)\n      else\n        Puppet::Util::Package::Version::Range::Eq.new(Debian.parse(default_version))\n      end","handlingStrategy":"type-guard","validationCode":"def range_string?(v)\n  v.is_a?(String) && !v.strip.empty?\nend","typeGuard":"def range_input?(v)\n  v.is_a?(String)\nend","tryCatchPattern":"begin\n  Puppet::Util::Package::Version::Range.parse(str, version_class)\nrescue Puppet::Util::Package::Version::Range::ValidationFailure\n  nil\nend","preventionTips":["Join token arrays and stringify symbols before calling Range.parse.","Give unset constraints an explicit default (bare current version) instead of passing nil."],"tags":["puppet","version-range","package-version","type-error","validation"],"backgroundTag":"version-string-validation","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}