{"record":{"id":"6cc6e7d1cb3d5fc5","repo":"tailscale/tailscale","slug":"usage-tailscale-ssh-user-host","errorCode":null,"errorMessage":"usage: tailscale ssh [user@]<host>","messagePattern":"usage: tailscale ssh \\[user@\\]<host>","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/tailscale/cli/ssh.go","lineNumber":55,"sourceCode":"\nThe 'tailscale ssh' wrapper adds a few things:\n\n* It resolves the destination server name in its arguments using MagicDNS,\n  even if --accept-dns=false.\n* It works in userspace-networking mode, by supplying a ProxyCommand to the\n  system 'ssh' command that connects via a pipe through tailscaled.\n* It automatically checks the destination server's SSH host key against the\n  node's SSH host key as advertised via the Tailscale coordination server.\n`),\n\tExec: runSSH,\n}\n\nfunc runSSH(ctx context.Context, args []string) error {\n\tif runtime.GOOS == \"darwin\" && version.IsMacAppStore() && !envknob.UseWIPCode() {\n\t\treturn errors.New(\"The 'tailscale ssh' subcommand is not available on macOS builds distributed through the App Store or TestFlight.\\nInstall the Standalone variant of Tailscale (download it from https://pkgs.tailscale.com), or use the regular 'ssh' client instead.\")\n\t}\n\tif len(args) == 0 {\n\t\treturn errors.New(\"usage: tailscale ssh [user@]<host>\")\n\t}\n\targ, argRest := args[0], args[1:]\n\tusername, host, ok := strings.Cut(arg, \"@\")\n\tif !ok {\n\t\thost = arg\n\t\tusername = \"\"\n\t}\n\n\tst, err := localClient.Status(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprefs, err := localClient.GetPrefs(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/tailscale/cli/ssh.go#L37-L73","documentation":"runSSH requires at least one positional target argument. With len(args) == 0 it returns a usage error immediately — no connection or name resolution is attempted. The accepted form is [user@]host, with extra args forwarded to ssh itself.","triggerScenarios":"`tailscale ssh` with no arguments; a script interpolating an empty destination variable (`tailscale ssh \"${DEST}\"`). The macOS App Store check runs first, so on those builds you'd see the platform error instead.","commonSituations":"Empty variables in automation; forgetting the destination after `tailscale ssh`; shell functions that conditionally append the host.","solutions":["Pass a target: `tailscale ssh user@host` (user@ is optional)","Guard variables in scripts: `: \"${DEST:?destination required}\"` before the call"],"exampleFix":"// before\n$ tailscale ssh\nusage: tailscale ssh [user@]<host>\n\n// after\n$ tailscale ssh admin@server","handlingStrategy":"validation","validationCode":"if dest == \"\" {\n\treturn errors.New(\"tailscale ssh requires [user@]<host>\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard destination variables: `: \"${DEST:?required}\"`","Validate the [user@]host form before invoking"],"tags":["tailscale","ssh","cli","argument-validation"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}