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

The provider for this Vagrant-managed machine is reporting t

Error message

The provider for this Vagrant-managed machine is reporting that it
is not yet ready for SSH. Depending on your provider this can carry
different meanings. Make sure your machine is created and running and
try again. Additionally, check the output of `vagrant status` to verify
that the machine is in the state that you expect. If you continue to
get this error message, please view the documentation for the provider
you're using.

What it means

The shell provisioner (POSIX path) must upload the script to the guest before running it. It wraps machine.ssh_info in retryable(on: SSHNotReady, tries: 3, sleep: 2) and raises Vagrant::Errors::SSHNotReady when ssh_info is still nil after three attempts — meaning the provider cannot yet report how to reach the machine over SSH.

Source

Thrown at plugins/provisioners/shell/provisioner.rb:114

      # This is the provision method called if SSH is what is running
      # on the remote end, which assumes a POSIX-style host.
      def provision_ssh(args)
        env = config.env.map { |k,v| "#{k}=#{quote_and_escape(v.to_s)}" }
        env = env.join(" ")

        command =  "chmod +x '#{upload_path}'"
        command << " &&"
        command << " #{env}" if !env.empty?
        command << " #{upload_path}#{args}"

        with_script_file do |path|
          # Upload the script to the machine
          @machine.communicate.tap do |comm|
            # Reset upload path permissions for the current ssh user
            info = nil
            retryable(on: Vagrant::Errors::SSHNotReady, tries: 3, sleep: 2) do
              info = @machine.ssh_info
              raise Vagrant::Errors::SSHNotReady if info.nil?
            end

            comm.upload(path.to_s, upload_path)
            user = info[:username]
            comm.sudo("chown -R #{user} #{upload_path}",
                      error_check: false)

            if config.name
              @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
                                      script: "script: #{config.name}"))
            elsif config.path
              @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
                                      script: path.to_s))
            else
              @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
                                      script: "inline script"))
            end

View on GitHub (pinned to 35f3160f4a)

Solutions

  1. Run vagrant status and confirm the machine reports 'running', then retry
  2. Verify vagrant ssh connects without prompts before provisioning
  3. Fix guest-side SSH: install/start sshd, correct config.ssh.username / private_key_path
  4. For provider plugins, update them so ssh_info is populated before the provision action runs

Example fix

# before
vagrant provision web   # machine still booting -> SSHNotReady

# after
vagrant up web && vagrant ssh web -c 'exit' && vagrant provision web
Defensive patterns

Strategy: retry

Validate before calling

# programmatic drivers: require a running machine with ssh_info
return unless machine.state.id == :running && !machine.ssh_info.nil?

Type guard

def ssh_ready?(machine)
  machine.state.id == :running && !machine.ssh_info.nil?
end

Try / catch

retries = 5
begin
  machine.provision
rescue Vagrant::Errors::SSHNotReady
  retries -= 1
  raise if retries.zero?
  sleep 4
  retry
end

Prevention

When it happens

Trigger: vagrant provision / vagrant up running the shell provisioner while the machine is not created, suspended, halted, or still booting; a provider (cloud or custom plugin) that returns nil from ssh_info; broken config.ssh settings or a guest without a running sshd.

Common situations: Provisioning too soon after vagrant up; boxes missing guest additions or sshd; wrong ssh username/port/key config; cloud VMs still initializing; machine actually in 'poweroff'/'not_created' state.

Related errors


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