hashicorp/vagrant · error · Vagrant::Errors::CopyPrivateKeyFailed

Vagrant failed to copy the default insecure private key into

Error message

Vagrant failed to copy the default insecure private key into your
home directory. This is usually caused by a permissions error.
Please make sure the permissions of the source is readable and
the destination is writable.

Source: %{source}
Destination: %{destination}

What it means

Raised as Vagrant::Errors::CopyPrivateKeyFailed from copy_insecure_private_keys (lib/vagrant/environment.rb:1094) when FileUtils.cp of the bundled source keys/vagrant file into the default insecure private key path under the Vagrant home (~/.vagrant.d/...) raises Errno::EACCES — the destination (or source) is not writable/readable due to permissions.

Source

Thrown at lib/vagrant/environment.rb:1094

    # `default_private_keys_directory` contains the list of valid private
    # keys supported by Vagrant.
    #
    # NOTE: The keys are copied because `ssh` requires that the key is chmod
    # 0600, but if Vagrant is installed as a separate user, then the
    # effective uid won't be able to read the key. So the key is copied
    # to the home directory and chmod 0600.
    def copy_insecure_private_keys
      # First setup the deprecated single key path
      if !@default_private_key_path.exist?
        @logger.info("Copying private key to home directory")

        source      = File.expand_path("keys/vagrant", Vagrant.source_root)
        destination = @default_private_key_path

        begin
          FileUtils.cp(source, destination)
        rescue Errno::EACCES
          raise Errors::CopyPrivateKeyFailed,
            source: source,
            destination: destination
        end
      end

      if !Util::Platform.windows?
        # On Windows, permissions don't matter as much, so don't worry
        # about doing chmod.
        if Util::FileMode.from_octal(@default_private_key_path.stat.mode) != "600"
          @logger.info("Changing permissions on private key to 0600")
          @default_private_key_path.chmod(0600)
        end
      end

      # Now setup the key directory
      Dir.glob(File.expand_path("keys/vagrant.key.*", Vagrant.source_root)).each do |source|
        destination = default_private_keys_directory.join(File.basename(source))
        default_private_key_paths << destination

View on GitHub (pinned to 35f3160f4a)

Solutions

  1. Fix ownership of the destination tree: `sudo chown -R $(id -u):$(id -g) ~/.vagrant.d` and ensure it is writable (chmod u+w)
  2. Verify the source is readable (it ships inside the Vagrant install; a broken install re-install fixes it)
  3. If $HOME cannot be made writable, point Vagrant elsewhere: `export VAGRANT_HOME=/writable/path/vagrant.d`
  4. Avoid running vagrant as root/mismatched users in the same home

Example fix

# before
$ sudo chown -R root:root ~/.vagrant.d   # (or created by earlier sudo run)
$ vagrant up   # CopyPrivateKeyFailed

# after
$ sudo chown -R $(id -u):$(id -g) ~/.vagrant.d
$ vagrant up
Defensive patterns

Strategy: validation

Validate before calling

home = ENV["VAGRANT_HOME"] || File.expand_path("~/.vagrant.d")
raise ArgumentError, "#{home} not writable — key copy will fail" unless File.writable?(home)
# source ships with the install; destination is home/insecure_private_key

Try / catch

begin
  env = Vagrant::Environment.new
rescue Vagrant::Errors::CopyPrivateKeyFailed => e
  abort "Cannot copy key #{e.extra_data[:source]} -> #{e.extra_data[:destination]}: fix permissions"
end

Prevention

When it happens

Trigger: First run on a machine where the home directory's key location is not writable by the current user — root-owned ~/.vagrant.d after earlier sudo use, hardened read-only home, or a VAGRANT_HOME path without write permission — so copying the default key fails during environment setup.

Common situations: sudo vagrant used once, then normal user; home directories on locked-down corporate images; running as a service account whose $HOME is not writable.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of hashicorp/vagrant@35f3160f4a (2026-08-21). Data as JSON: /api/errors/d89bf2f53a623c89. Report an issue: GitHub.