I asked a Claude Code agent — an AI process that runs real shell commands on my behalf — to do something simple: SSH from my Linux dev box into a Mac and run a Google Workspace CLI that only ships for macOS. SSH is just the remote-login tool that lets one machine run commands on another. The agent typed ssh <host>, hit enter, and got back:
Too many authentication failures
Which is a strange way to fail, because I hadn’t given it too many passwords. I’d given it zero.
Here’s what actually happened, and it’s the kind of thing that bites anyone wiring an agent or a CI job into a fleet of machines. When you run bare ssh <host>, ssh-agent — the little keychain that holds your login keys — helpfully offers every key it’s holding, one after another, hoping one fits. Think of it as showing up at a door and trying all forty keys on your ring. The Mac counts each wrong key against a hard limit (MaxAuthTries, usually six) and locks the connection before the agent ever reaches the correct key. So it failed and ate into the lockout budget on every attempt.
Two other things were quietly wrong. ssh <host> defaults to logging in as your local username, and my Linux user didn’t match the Mac account — so even the “right” key was being offered for the wrong person. And the first thing I tried, just naming the correct user, still let the agent churn keys. It took three failed rounds before I stopped guessing and forced the machine to state its intent explicitly.
The fix is to stop being helpful and be precise. Offer exactly one key, for exactly one user, using exactly one auth method:
The explicit, non-churning SSH connect pattern give me the detail
ssh -o IdentitiesOnly=yes \
-o PreferredAuthentications=publickey \
-i ~/.ssh/the_one_key \
correct_user@host \
'whoami && which gam'IdentitiesOnly=yes is the load-bearing flag: it tells ssh to use only the key named with -i and ignore everything ssh-agent wants to volunteer. That single option is what keeps you under MaxAuthTries.
Then the second trap. That which gam probe came back empty even after login succeeded. Non-interactive SSH on macOS skips /etc/paths, so Homebrew binaries in /opt/homebrew/bin aren’t on PATH. Either call the full path, or wrap the command in a login shell: bash -lc 'gam ...'.
The habit worth stealing isn’t the flag list. It’s sending a two-word probe — whoami && which <tool> — before you compose the real command. It tells you who you actually logged in as and whether your tool is even reachable, in one cheap round trip, instead of debugging a twelve-line remote invocation that was doomed at the handshake.
Agents fail differently than humans do. A person tries one key and stops. An agent lets the machine’s “helpful” defaults run to their conclusion — and the defaults were written to be convenient, not safe. When you automate a connection, spell out every choice the tooling would otherwise make for you. Convenience is where the silent lockouts live.