puppetlabs/puppet · error · Puppet::Util::Package::Version::Range::ValidationFailure
Unable to parse '#{simple}' as a version range identifier
Error message
Unable to parse '#{simple}' as a version range identifier What it means
Inside Range.parse (range.rb:37): each whitespace-separated token must match FULL_REGEX = /\A((?:[<>=])*)(.+)\Z/. The capture group (.+) requires at least one version character after the operator run, so a bare operator token (no version attached) fails to match and raises ValidationFailure 'Unable to parse ... as a version range identifier'. Because tokens are split on /\s+/, writing a space between operator and version turns the operator into its own token and hits exactly this raise.
Source
Thrown at lib/puppet/util/package/version/range.rb:37
# * ex. `"1.0.0"`, `"1.2.3-pre"`
# * Inequalities
# * ex. `">1.0.0"`, `"<3.2.0"`, `">=4.0.0"`
# * Range Intersections (min is always first)
# * ex. `">1.0.0 <=2.3.0"`
#
RANGE_SPLIT = /\s+/
FULL_REGEX = /\A((?:[<>=])*)(.+)\Z/
# @param range_string [String] the version range string to parse
# @param version_class [Version] a version class implementing comparison operators and parse method
# @return [Range] a new {Range} instance
# @api public
def self.parse(range_string, version_class)
raise ValidationFailure, "Unable to parse '#{range_string}' as a string" unless range_string.is_a?(String)
simples = range_string.split(RANGE_SPLIT).map do |simple|
match, operator, version = *simple.match(FULL_REGEX)
raise ValidationFailure, "Unable to parse '#{simple}' as a version range identifier" unless match
case operator
when '>'
Gt.new(version_class.parse(version))
when '>='
GtEq.new(version_class.parse(version))
when '<'
Lt.new(version_class.parse(version))
when '<='
LtEq.new(version_class.parse(version))
when ''
Eq.new(version_class.parse(version))
else
raise ValidationFailure, "Operator '#{operator}' is not implemented"
end
end
simples.size == 1 ? simples[0] : MinMax.new(simples[0], simples[1])
endView on GitHub (pinned to e227c27540)
Solutions
- Remove the space between operator and version: '>1.0', '>=2.0', '<=3.2.0'.
- Normalize before parsing: squeeze each operator token onto its version (e.g. str.gsub(/([<>=]+)\s+/, '\1')).
- Pre-validate each token against /\A(?:[<>=]*)(.+)\Z/ plus a non-empty operator when an operator was intended.
- Rescue Range::ValidationFailure and report the offending token to the user.
Example fix
// before rng = Puppet::Util::Package::Version::Range.parse(constraint, version_class) # constraint = '>= 1.2.0' // after normalized = constraint.strip.gsub(/([<>=]+)\s+/, '\1') rng = Puppet::Util::Package::Version::Range.parse(normalized, version_class)
Defensive patterns
Strategy: validation
Validate before calling
def range_tokens_ok?(str)
str.is_a?(String) && str.split(/\s+/).all? { |t| t.match?(/\A(?:[<>=]*)(.+\z)/m) && !t.match?(/\A[<>=]+\z/) }
end Try / catch
begin
Range.parse(normalized, version_class)
rescue Puppet::Util::Package::Version::Range::ValidationFailure => e
raise ArgumentError, "bad range #{str.inspect}: #{e.message}"
end Prevention
- Normalize '> 1.0' to '>1.0' with gsub(/([<>=]+)\s+/, '\1') before parsing.
- Document the no-space operator format wherever constraints are user-editable (Hiera keys, module READMEs).
When it happens
Trigger: Range.parse('> 1.0', klass) splits into '>' and '1.0'; the token '>' has an empty (.+) part so match is nil and line 37 raises. Also '>= 2.0 <= 3.0' (both operators detached), or any token made only of [<>=] characters.
Common situations: Version constraints authored for readability as '>= 1.2.0' (with a space) in manifests or Hiera data; constraints copied from Gemfile/pip syntax that assumes space-tolerant parsing; templates interpolating "#{op} #{ver}" with an unintended space.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to parse '#{range_string}' as a string
- Operator '#{operator}' is not implemented
- Invalid 'version_range' field in metadata.json: %{err}
- Unable to parse '#{ver}' as a debian version identifier
- #{version} is not a valid ruby gem version.
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/10c6cb4e85986168.
Report an issue: GitHub.