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

The `ssh` executable found in the PATH is a PuTTY Link SSH c

Error message

The `ssh` executable found in the PATH is a PuTTY Link SSH client.
Vagrant is only compatible with OpenSSH SSH clients. Please install
an OpenSSH SSH client or manually SSH in using your existing client
using the information below.

Host: %{host}
Port: %{port}
Username: %{username}
Private key: %{key_path}

What it means

On Windows, Vagrant::Util::SSH.exec defensively executes the discovered ssh executable with no arguments and scans stdout for 'PuTTY Link' / 'Plink: command-line connection utility'; if the PATH ssh is actually plink underneath, it raises SSHIsPuttyLink (Vagrant supports OpenSSH clients only) with the connection details for manual use.

Source

Thrown at lib/vagrant/util/ssh.rb:104

        if !ssh_path
          if Platform.windows?
            raise Errors::SSHUnavailableWindows,
              host: ssh_info[:host],
              port: ssh_info[:port],
              username: ssh_info[:username],
              key_path: ssh_info[:private_key_path].join(", ")
          end

          raise Errors::SSHUnavailable
        end

        if Platform.windows?
          # On Windows, we need to detect whether SSH is actually "plink"
          # underneath the covers. In this case, we tell the user.
          r = Subprocess.execute(ssh_path)
          if r.stdout.include?("PuTTY Link") || r.stdout.include?("Plink: command-line connection utility")
            raise Errors::SSHIsPuttyLink,
              host: ssh_info[:host],
              port: ssh_info[:port],
              username: ssh_info[:username],
              key_path: ssh_info[:private_key_path].join(", ")
          end
        end

        # If plain mode is enabled then we don't do any authentication (we don't
        # set a user or an identity file)
        plain_mode = opts[:plain_mode]

        options = {}
        options[:host] = ssh_info[:host]
        options[:port] = ssh_info[:port]
        options[:username] = ssh_info[:username]
        options[:private_key_path] = ssh_info[:private_key_path]

        log_level = ssh_info[:log_level] || "FATAL"

View on GitHub (pinned to 35f3160f4a)

Solutions

  1. Remove or rename the plink-as-ssh shim so a real OpenSSH client resolves for `ssh`
  2. Install the Windows OpenSSH Client (or Git for Windows) and ensure it precedes the shim in PATH
  3. Or keep PuTTY and connect manually with the Host/Port/Username/key details the error prints

Example fix

# before: shim dir shadows the real ssh
> where ssh
C:\Tools\shims\ssh.exe        (plink wrapper)

# after
> ren C:\Tools\shims\ssh.exe ssh-plink.cmd
> where ssh
C:\Windows\System32\OpenSSH\ssh.exe
Defensive patterns

Strategy: validation

Validate before calling

ssh = Vagrant::Util::Which.which('ssh')
if ssh
  banner = `#{ssh} 2>&1`.to_s
  abort 'ssh resolves to PuTTY plink; install a real OpenSSH client' if banner.include?('PuTTY Link')
end

Try / catch

begin
  Vagrant::Util::SSH.exec(machine.ssh_info)
rescue Vagrant::Errors::SSHIsPuttyLink => e
  warn e.message # manual connection details included
  system('putty', '-ssh', "#{machine.ssh_info[:username]}@#{machine.ssh_info[:host]}", '-P', machine.ssh_info[:port].to_s)
end

Prevention

When it happens

Trigger: `vagrant ssh` on Windows where plink.exe is exposed as ssh — a renamed/copied plink, a shim or wrapper directory (chocolatey shims, custom bin) forwarding ssh to PuTTY's plink — so the detection string appears in the tool's banner output.

Common situations: Machines with PuTTY-centric corporate tooling; a bin dir early in PATH shadowing OpenSSH with a plink alias.

Related errors


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