macOS: zsh: command not found: brew
Hi, it's BlueByte. If brew says "command not found" right after installing, don't reinstall — Homebrew is there, your shell just doesn't know where to look. On Apple silicon it lives somewhere the default PATH doesn't include. Let's confirm that's the issue and add it once, for good.
What the error means
Right after installing Homebrew, running it fails:
zsh: command not found: brewHomebrew is installed — the shell just does not know where to find it, because its location is not on your PATH. The installer even prints the two lines you need at the end of its output, and this happens when you miss them or open a new terminal that never ran them.
Why the shell can't find brew
On Apple silicon Macs, Homebrew installs to /opt/homebrew, which is not on the default PATH. On older Intel Macs it installs to /usr/local, which usually is — so the same install "just works" on Intel and appears broken on Apple silicon. The other reasons a working setup breaks: you added the PATH line to the wrong file (~/.zshrc in a non-interactive context, say), or to a shell you are no longer using after switching from bash to zsh.
Confirm it's PATH, and find where brew lives
Check Homebrew is actually installed and where, then which shell and architecture you run:
ls /opt/homebrew/bin/brew /usr/local/bin/brew 2>/dev/null
echo $SHELL
uname -marm64 from uname -m means Apple silicon (/opt/homebrew); x86_64 means Intel (/usr/local). $SHELL tells you which profile file to edit. If ls finds the binary but the shell cannot, it is purely a PATH problem.
Add Homebrew to PATH, permanently
- Add Homebrew to the current shell right now:
eval "$(/opt/homebrew/bin/brew shellenv)"brew works immediately in this terminal.
- Make it permanent for every new shell by appending the same line to your zsh profile:
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile- On an Intel Mac, use
/usr/local/bin/brewinstead:
eval "$(/usr/local/bin/brew shellenv)"A real case: a new M-series MacBook
You install Homebrew on a new M-series MacBook, close the installer's terminal, open a fresh one, and brew --version says "command not found". ls /opt/homebrew/bin/brew shows the binary exists and uname -m prints arm64, so it is only a PATH issue. You run echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile, open a new terminal, and which brew now returns /opt/homebrew/bin/brew. Every future shell finds it because the line lives in your login profile.
Confirm a fresh terminal finds it
Open a new terminal and confirm brew is found and on PATH:
which brew # /opt/homebrew/bin/brew
brew --versionIf a fresh terminal finds it, the profile change took effect for all future sessions — not just the one you edited in.
Keep it from recurring
Add the shellenv line to your profile once, right after installing, and keep it in ~/.zprofile (modern macOS uses zsh). If you sync dotfiles across machines, guard the path so an Intel and an Apple-silicon Mac each load the right one.
How this differs from a real brew error
"command not found: brew" is a PATH problem — the program exists but the shell cannot find it. That is different from a Homebrew error like "Permission denied" or a failed formula install, where brew is found and runs but the operation fails. When the shell can't find brew at all, it is PATH — add the shellenv line.
Related questions
How do I know if I'm on Apple silicon or Intel?
Run uname -m: arm64 is Apple silicon (Homebrew in /opt/homebrew), x86_64 is Intel (/usr/local).
It works in one terminal but not new ones.
You ran the eval command in the current shell but did not add it to ~/.zprofile. Append it there so every new shell loads Homebrew's PATH.
I use bash, not zsh.
Put the same eval line in ~/.bash_profile instead of ~/.zprofile. The command is identical; only the profile file differs.
Why ~/.zprofile and not ~/.zshrc?
Either works, but .zprofile runs for login shells and is Homebrew's documented choice, which keeps the PATH set consistently across terminals and login sessions.
I moved from an Intel Mac and brew still points at /usr/local.
Your profile has the Intel path. Update the shellenv line to /opt/homebrew/bin/brew for Apple silicon, and reinstall Homebrew if it was migrated rather than freshly installed.
References
Haneul Seo
Infrastructure engineer · 10+ years running Linux fleets
More in this category
systemd: Start request repeated too quickly
systemd refuses to start a unit that was started more than StartLimitBurst times (default 5) within StartLimitIntervalSec (default 10s), and Restart= counts against that limit. With the 100 ms default RestartSec a crashing service burns all five attempts in under a second. Find the real crash in the journal, fix it, run reset-failed, and give restarts room with RestartSec.
SSH: Received disconnect ... Too many authentication failures
Your agent is offering more keys than the server will let you try. Every public key sshd looks at burns one of the MaxAuthTries attempts — six by default, often three on a hardened host — so the right key never gets its turn and the server hangs up before you type anything. IdentitiesOnly=yes with an explicit IdentityFile pins the connection to one key and the attempt count drops to one.
Active Directory: replication fails with error 1722, The RPC server is unavailable
RPC reports 1722 (0x6ba, RPC_S_SERVER_UNAVAILABLE) when a lower layer fails to connect, so the real fault is almost never RPC itself — it is DNS, a blocked port, or a host-side setting on one of the two domain controllers. repadmin tells you which partner is failing, dcdiag /test:dns rules out name resolution, and Test-NetConnection plus the dynamic port range settle the firewall question. The most common miss is a rule that allows TCP 135 but not 49152–65535.
Windows Server RDS: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license
The 120-day RD Licensing grace period ended and the session host has no usable license server, so it refuses sessions. GetGracePeriodDays returning DaysLeft 0 and an empty SpecifiedLSList confirm it in seconds. The fix is a real, activated license server with CALs that are new enough for the host — a 2019 CAL cannot serve a 2022 session host — configured through the deployment or the Licensing policies, plus RPC ports open between the two.
Windows 11: "Your organization's security policies block unauthenticated guest access" when opening a NAS share (0x80070035)
The SMB client on Windows 10 Enterprise/Education/Pro for Workstations, Windows 11 Pro and Windows Server 2019+ refuses guest logons by default, and Windows 11 24H2 Enterprise/Pro/Education also requires SMB signing, which guest sessions can't do. A NAS share that only offers guest access therefore fails with the 'block unauthenticated guest access' dialog, Error code 0x80070035, or System error 3227320323, and Event ID 31017 'Rejected an insecure guest logon' lands in the SmbClient/Security log. The fix Microsoft recommends is a real account on the NAS and signing support in its firmware; Set-SmbClientConfiguration -EnableInsecureGuestLogons $true (plus -RequireSecuritySignature $false on 24H2) is the escape hatch, and it costs you signing and encryption on that client.
Ubuntu/Debian: E: Could not get lock /var/lib/dpkg/lock-frontend — who holds it and how to wait for it
Another package manager, usually Ubuntu's unattended-upgrades fired by a persistent systemd timer at boot, holds the dpkg frontend lock while your apt-get runs. apt-get gives up at once while apt waits because Ubuntu ships binary::apt::DPkg::Lock::Timeout "120" for the apt binary only. Read the PID from the message, let the run finish or pass -o DPkg::Lock::Timeout=<seconds> to apt-get, run dpkg --configure -a only after a genuinely interrupted run, and never delete the lock file: it is an fcntl lock the kernel releases when the holder exits.