puppetlabs/puppet · error · ValidationFailure

Unable to parse '#{ver}' as a debian version identifier

Error message

Unable to parse '#{ver}' as a debian version identifier

What it means

Raised by Puppet::Util::Package::Version::Debian.parse when the input String does not fully match the Debian version grammar REGEX_FULL_RX = /\A(?:([0-9]+):)?([.+~0-9a-zA-Z-]+?)(?:-([.+~0-9a-zA-Z]*))?\Z/ (epoch:upstream-version with optional -debian-revision). ValidationFailure subclasses ArgumentError, so it is catchable as ArgumentError. Any character outside [0-9a-zA-Z.+~-], an empty upstream part, surrounding whitespace, or a stray ':' causes the match (and thus the parse) to fail.

Source

Thrown at lib/puppet/util/package/version/debian.rb:24

    # Version string matching regexes
    REGEX_EPOCH = '(?:([0-9]+):)?'
    # alphanumerics and the characters . + - ~ , starts with a digit, ~ only of debian_revision is present
    REGEX_UPSTREAM_VERSION = '([\.\+~0-9a-zA-Z-]+?)'
    # alphanumerics and the characters + . ~
    REGEX_DEBIAN_REVISION = '(?:-([\.\+~0-9a-zA-Z]*))?'

    REGEX_FULL    = REGEX_EPOCH + REGEX_UPSTREAM_VERSION + REGEX_DEBIAN_REVISION.freeze
    REGEX_FULL_RX = /\A#{REGEX_FULL}\Z/

    class ValidationFailure < ArgumentError; end

    def self.parse(ver)
      raise ValidationFailure, "Unable to parse '#{ver}' as a string" unless ver.is_a?(String)

      match, epoch, upstream_version, debian_revision = *ver.match(REGEX_FULL_RX)

      raise ValidationFailure, "Unable to parse '#{ver}' as a debian version identifier" unless match

      new(epoch.to_i, upstream_version, debian_revision).freeze
    end

    def to_s
      s = @upstream_version
      s = "#{@epoch}:#{s}" if @epoch != 0
      s = "#{s}-#{@debian_revision}" if @debian_revision
      s
    end
    alias inspect to_s

    def eql?(other)
      other.is_a?(self.class) &&
        @epoch.eql?(other.epoch) &&
        @upstream_version.eql?(other.upstream_version) &&
        @debian_revision.eql?(other.debian_revision)
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Normalize the string before parsing: strip whitespace, drop a leading 'v', and reject empty strings.
  2. Pre-validate against Puppet::Util::Package::Version::Debian::REGEX_FULL_RX (match with \A/\Z anchoring) and skip or fallback when it does not match.
  3. Rescue Puppet::Util::Package::Version::Debian::ValidationFailure (an ArgumentError) at the call site and degrade to a plain version string or installed/latest.
  4. Check the value against Debian policy: optional numeric epoch + ':', upstream version of [0-9a-zA-Z.+~-], optional '-' + revision of [0-9a-zA-Z.+~].

Example fix

// before
ver = Puppet::Util::Package::Version::Debian.parse(pkg_version) # raises on '1.0 beta'

// after
def parse_debian_safe(str)
  return nil unless str.is_a?(String)
  return nil unless str =~ /\A(?:([0-9]+):)?([.+~0-9a-zA-Z-]+?)(?:-([.+~0-9a-zA-Z]*))?\Z/
  Puppet::Util::Package::Version::Debian.parse(str)
end
ver = parse_debian_safe(pkg_version.strip.sub(/\Av/, '')) || fallback
Defensive patterns

Strategy: validation

Validate before calling

def parseable_debian?(str)
  str.is_a?(String) && str.match?(Puppet::Util::Package::Version::Debian::REGEX_FULL_RX)
end

ver = parseable_debian?(candidate) ? Puppet::Util::Package::Version::Debian.parse(candidate.strip) : nil

Try / catch

begin
  ver = Puppet::Util::Package::Version::Debian.parse(candidate)
rescue Puppet::Util::Package::Version::Debian::ValidationFailure => e
  Puppet.err("invalid debian version #{candidate.inspect}: #{e.message}")
  ver = nil
end

Prevention

When it happens

Trigger: Calling Debian.parse with: '1.0_beta' or '1.0 beta' (underscore/space not in the character class), '' (upstream part is +? so at least one char required), ' 1.0' (leading whitespace, anchored \A), '1:2.3:4' (second colon cannot match), '1.0~rc1-x's are fine but '1..2.3!' is not. Passing a non-String (Integer, Symbol, nil) hits the separate 'as a string' raise at debian.rb:20 instead.

Common situations: Puppet package resources whose ensure is a version string copied from upstream release tags ('v1.2.3' is actually parseable since 'v' is alphanumeric, but '1.2.3-rc1+b1!' style strings from GitHub releases are not); versions read from YAML/JSON data files that carry whitespace or newlines; feeding RPM-style '1:1.2.3-4.el7' with extra revision chars, or pip-style '1.0.post1' containing characters Debian allows only in certain positions.

Understand the failure class

Related errors


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