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 ssh_run middleware (`vagrant ssh -c "cmd"`) uses the same contract as ssh_exec: env/machine ssh_info must be non-nil or the provider is declaring the machine not ready for SSH, and SSHNotReady is raised before the remote command is built. The difference from ssh_exec is only the entry point — running a one-off command instead of an interactive session.

Source

Thrown at lib/vagrant/action/builtin/ssh_run.rb:32

      # mirror the output to the UI. The resulting exit status of the command
      # will exist in the `:ssh_run_exit_status` key in the environment.
      class SSHRun
        # For quick access to the `SSH` class.
        include Vagrant::Util

        def initialize(app, env)
          @app    = app
          @logger = Log4r::Logger.new("vagrant::action::builtin::ssh_run")
        end

        def call(env)
          # Grab the SSH info from the machine or the environment
          info = env[:ssh_info]
          info ||= env[:machine].ssh_info

          # If the result is nil, then the machine is telling us that it is
          # not yet ready for SSH, so we raise this exception.
          raise Errors::SSHNotReady if info.nil?

          info[:private_key_path] ||= []

          if info[:keys_only] && info[:private_key_path].empty?
            raise Errors::SSHRunRequiresKeys
          end

          # Get the command and wrap it in a login shell
          command = ShellQuote.escape(env[:ssh_run_command], "'")

          if env[:machine].config.vm.communicator == :winssh
            shell = env[:machine].config.winssh.shell
          else
            shell = env[:machine].config.ssh.shell
          end

          if shell == "cmd"
            # Add an extra space to the command so cmd.exe quoting works

View on GitHub (pinned to 35f3160f4a)

Solutions

  1. Check `vagrant status` and bring the machine up (`vagrant up`) before issuing `vagrant ssh -c`.
  2. For scripts, chain the commands so up completes first: `vagrant up && vagrant ssh -c '...'`.
  3. If state is abnormal ('aborted', stuck), `vagrant reload` or `vagrant destroy && vagrant up`.

Example fix

# before
vagrant ssh -c 'docker ps'   # machine halted => SSHNotReady

# after
vagrant up && vagrant ssh -c 'docker ps'
Defensive patterns

Strategy: try-catch

Validate before calling

# Shell: run remote commands only against a running machine
state=$(vagrant status --machine-readable | awk -F, '$3=="state-id"{print $4}')
[ "$state" = "running" ] && vagrant ssh -c "$CMD" || { vagrant up >/dev/null && vagrant ssh -c "$CMD"; }

Type guard

# Ruby: predicate guard before ssh_run-style APIs
def runnable?(machine)
  %w[running].include?(machine.state.id.to_s) && !machine.ssh_info.nil?
end

Try / catch

# Ruby: one retry after up, then give up with a clear message
begin
  env[:machine].communicate.execute(cmd)
rescue Vagrant::Errors::SSHNotReady
  env[:machine].action("up")
  env[:machine].communicate.execute(cmd)
end

Prevention

When it happens

Trigger: Running `vagrant ssh -c "uptime"` (or any API path that sets ssh_run_command) while machine.ssh_info returns nil — machine not created, halted, aborted, or provider container stopped (lib/vagrant/action/builtin/ssh_run.rb:23-34).

Common situations: Automation that runs a command via `vagrant ssh -c` right after triggering up asynchronously; provisioning-style scripts that assume the VM stays running; machine crashed mid-boot leaving state 'aborted'.

Related errors


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