ruby/ruby · error · Gem::OptionParser::InvalidArgument

#{key_file}: does not exist

Error message

#{key_file}: does not exist

What it means

open_private_key reads the file given to -K/--key with OpenSSL::PKey.read; Errno::ENOENT is re-raised as Gem::OptionParser::InvalidArgument '<path>: does not exist'. The check runs during execute (e.g. when signing with -s or re-signing with -R), and an encrypted key additionally consults GEM_PRIVATE_KEY_PASSPHRASE.

Source

Thrown at lib/rubygems/commands/cert_command.rb:101

  end

  def open_cert(certificate_file)
    check_openssl
    OpenSSL::X509::Certificate.new File.read certificate_file
  rescue Errno::ENOENT
    raise Gem::OptionParser::InvalidArgument, "#{certificate_file}: does not exist"
  rescue OpenSSL::X509::CertificateError
    raise Gem::OptionParser::InvalidArgument,
      "#{certificate_file}: invalid X509 certificate"
  end

  def open_private_key(key_file)
    check_openssl
    passphrase = ENV["GEM_PRIVATE_KEY_PASSPHRASE"]
    key = OpenSSL::PKey.read File.read(key_file), passphrase
    key
  rescue Errno::ENOENT
    raise Gem::OptionParser::InvalidArgument, "#{key_file}: does not exist"
  rescue OpenSSL::PKey::PKeyError, ArgumentError
    raise Gem::OptionParser::InvalidArgument, "#{key_file}: invalid RSA, DSA, or EC key"
  end

  def execute
    check_openssl

    options[:add].each do |certificate|
      add_certificate certificate
    end

    options[:remove].each do |filter|
      remove_certificates_matching filter
    end

    options[:list].each do |filter|
      list_certificates_matching filter
    end

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Generate a key pair if absent: gem cert --build you@example.com
  2. Copy the existing key to the expected path (default ~/.gem/gem-private_key.pem, mode 0600)
  3. Pass an absolute path to -K

Example fix

# before
gem cert -K key.pem -C gem-public_cert.pem -s to_sign.pem
# InvalidArgument: key.pem: does not exist

# after
gem cert -K "$HOME/.gem/gem-private_key.pem" -C gem-public_cert.pem -s to_sign.pem
Defensive patterns

Strategy: validation

Validate before calling

key_path = File.expand_path('gem-private_key.pem', Gem.dir)
unless File.file?(key_path)
  abort 'no private key; run: gem cert --build you@example.com'
end
system('gem', 'cert', '-K', key_path, '-C', cert_path, '-R') or exit 1

Try / catch

begin
  cmd.invoke
rescue Gem::OptionParser::InvalidArgument => e
  raise unless e.message == "#{key_path}: does not exist"
  system('gem', 'cert', '--build', email) # provision key+cert, then retry manually
end

Prevention

When it happens

Trigger: `gem cert -K missing.pem -C cert.pem -s to_sign.pem`; first-ever signing on a machine where gem-private_key.pem was never generated or copied; a typo'd relative path.

Common situations: New CI runners lacking the developer's private key; key stored outside the working directory; scripts assuming `gem cert --build` already ran.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/0c49fc562d0253ff. Report an issue: GitHub.