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

Vagrant failed to copy the default insecure private key…

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.

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.

Appendix: 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)