puppetlabs/puppet · error · Puppet::Error

Cannot resolve pip version

Error message

Cannot resolve pip version

What it means

pip.rb:58 (pip_version): the provider discovers the pip version by running `<command> --version` and matching /^pip (\d+\.\d+\.?\d*)/; if no output line matches, it raises Puppet::Error 'Cannot resolve pip version'. The version gates behavior (e.g. which list/install flags are safe), so an unparseable version string aborts gem... pip package management before any operation.

Source

Thrown at lib/puppet/provider/package/pip.rb:58

      ["pip.exe"]
    else
      %w[pip pip-python pip2 pip-2]
    end
  end

  def self.pip_version(command)
    version = nil
    execpipe [quote(command), '--version'] do |process|
      process.collect do |line|
        md = line.strip.match(/^pip (\d+\.\d+\.?\d*).*$/)
        if md
          version = md[1]
          break
        end
      end
    end

    raise Puppet::Error, _("Cannot resolve pip version") unless version

    version
  end

  # Return an array of structured information about every installed package
  # that's managed by `pip` or an empty array if `pip` is not available.
  def self.instances(target_command = nil)
    if target_command
      command = target_command
      validate_command(command)
    else
      command = provider_command
    end

    packages = []
    return packages unless command

    command_options = ['freeze']

View on GitHub (pinned to e227c27540)

Solutions

  1. Run `<pipcmd> --version` yourself exactly as puppet does; the first line must look like 'pip 23.2.1 from ...'.
  2. Point the provider at a real pip executable (absolute path to the venv's bin/pip or /usr/bin/pip3) instead of a shim on PATH.
  3. Upgrade/reinstall the broken pip (`python -m pip install -U pip`) so --version output is standard.
  4. If you use pipx/uv/conda tooling, manage those environments with their own providers/execs, not the pip provider.

Example fix

# before
package { 'requests': ensure => installed, provider => 'pip' }  # pipcmd is a broken shim

# after
# pin the real interpreter's pip
package { 'requests': ensure => installed, provider => 'pip', install_options => ['--index-url', 'https://internal/simple'] }
# and ensure `puppet resource pip pipcmd=/usr/bin/pip3` (or PATH) resolves to a genuine pip
Defensive patterns

Strategy: validation

Validate before calling

# the exact parse the provider performs
out = `#{pip_cmd} --version`
ok = out.lines.any? { |l| l.strip =~ /^pip (\d+\.\d+\.?\d*)/ }
raise "puppet cannot parse '#{pip_cmd} --version' output" unless ok

Type guard

def puppet_parseable_pip?(cmd)
  `#{cmd} --version 2>&1`.match(/^pip (\d+\.\d+\.?\d*)/) ? true : false
rescue Errno::ENOENT
  false
end

Try / catch

begin
  Puppet::Type.type(:package).provider(:pip).instances
rescue Puppet::Error => e
  raise unless e.message == 'Cannot resolve pip version'
  # re-point provider at a known-good pip and retry
  Puppet[:pipcmd] = '/usr/bin/pip3'; retry
end

Prevention

When it happens

Trigger: A pip package resource (or instances enumeration) where the configured pip command's --version output does not start with 'pip x.y[.z]': a wrapper/virtualenv shim that prints extra banners, a pip so old it formats differently, a broken install where --version exits non-zero or prints to stderr only, or a command that is actually pipx/uv/conda masquerading as pip.

Common situations: pyenv/rvm-style shims that prepend output; customized corporate wrappers around pip; pip invoked through `python -m pip` with unusual stdout; Windows or localized environments altering the banner; leftover empty pip scripts after a python upgrade.

Related errors


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