puppetlabs/puppet · error · ArgumentError

Unable to convert a #{version.class.name} to a SemVer

Error message

Unable to convert a #{version.class.name} to a SemVer

What it means

PSemVerType.convert normalizes input for the SemVer type: nil and SemanticPuppet::Version pass through, Strings are parsed via SemanticPuppet::Version.parse, and any other class raises ArgumentError stating it cannot be converted to a SemVer. Unlike the new function (which accepts a Struct of parts), convert accepts only these three forms.

Source

Thrown at lib/puppet/pops/types/p_sem_ver_type.rb:53

    super ^ @ranges.hash
  end

  # Creates a SemVer version from the given _version_ argument. If the argument is `nil` or
  # a {SemanticPuppet::Version}, it is returned. If it is a {String}, it will be parsed into a
  # {SemanticPuppet::Version}. Any other class will raise an {ArgumentError}.
  #
  # @param version [SemanticPuppet::Version,String,nil] the version to convert
  # @return [SemanticPuppet::Version] the converted version
  # @raise [ArgumentError] when the argument cannot be converted into a version
  #
  def self.convert(version)
    case version
    when nil, SemanticPuppet::Version
      version
    when String
      SemanticPuppet::Version.parse(version)
    else
      raise ArgumentError, "Unable to convert a #{version.class.name} to a SemVer"
    end
  end

  # @api private
  def self.new_function(type)
    @new_function ||= Puppet::Functions.create_loaded_function(:new_Version, type.loader) do
      local_types do
        type 'PositiveInteger = Integer[0,default]'
        type 'SemVerQualifier = Pattern[/\A(?<part>[0-9A-Za-z-]+)(?:\.\g<part>)*\Z/]'
        type "SemVerPattern = Pattern[/\\A#{SemanticPuppet::Version::REGEX_FULL}\\Z/]"
        type 'SemVerHash = Struct[{major=>PositiveInteger,minor=>PositiveInteger,patch=>PositiveInteger,Optional[prerelease]=>SemVerQualifier,Optional[build]=>SemVerQualifier}]'
      end

      # Creates a SemVer from a string as specified by http://semver.org/
      #
      dispatch :from_string do
        param 'SemVerPattern', :str
      end

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass a full semantic version String: '1.9.0' (three segments; use the DSL new() parts form for programmatic construction)
  2. Or pass an existing SemanticPuppet::Version object; nil is also accepted
  3. Coerce numeric input to String and ensure it has major.minor.patch segments

Example fix

# before
Puppet::Pops::Types::PSemVerType.convert(1.9)   # ArgumentError
$v = SemVer[1]                                   # DSL equivalent

# after
Puppet::Pops::Types::PSemVerType.convert('1.9.0')
$v = SemVer['1.9.0']                             # or SemVer({major=>1,minor=>9,patch=>0})
Defensive patterns

Strategy: type-guard

Validate before calling

# accept only nil, Version, or String before calling convert
unless version.nil? || version.is_a?(SemanticPuppet::Version) || version.is_a?(String)
  raise ArgumentError, "expected a SemVer String or Version, got #{version.class}"
end

Type guard

def semver_input?(v)
  v.nil? || v.is_a?(SemanticPuppet::Version) || v.is_a?(String)
end

Try / catch

begin
  Puppet::Pops::Types::PSemVerType.convert(input)
rescue ArgumentError => e
  raise unless e.message =~ /to a SemVer/
  raise "invalid version #{input.inspect}: pass a String like '1.9.0'"
end

Prevention

When it happens

Trigger: Ruby-side: Puppet::Pops::Types::PSemVerType.convert(1.9), convert(:latest), or convert([1,2,3]). DSL-side: SemVer[1] or SemVer[3.2] - a bare number instead of a dotted version String or parts Struct.

Common situations: Passing a Float/Integer version (1.9 instead of '1.9.0'); passing a Hash of parts to the Ruby API (allowed by the DSL new function but not convert); version data read from YAML where '1.2.3' lost its quotes and became something else.

Related errors


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