What I saw
azd 1.25.4 prints this update banner on every command:
Update available: 1.25.4 -> 1.25.6
To update, run `brew uninstall azd && brew install --cask azure/azd/azd`
Following the suggested command fails:
$ brew uninstall azd && brew install --cask azure/azd/azd
Error: Refusing to load cask azure/azd/azd from untrusted tap azure/azd.
Run `brew trust --cask azure/azd/azd` or `brew trust azure/azd` to trust it.
Every obvious recovery a user might try also fails — including the ones that should let them escape the situation:
$ brew install azd
Error: Refusing to load cask azure/azd/azd from untrusted tap azure/azd.
$ brew upgrade azd
Error: Refusing to load cask azure/azd/azd from untrusted tap azure/azd.
$ brew uninstall --cask --force azd
Error: Refusing to load cask azure/azd/azd from untrusted tap azure/azd.
$ brew untap azure/azd
Error: Refusing to untap azure/azd because it contains the following installed formulae or casks:
azd
The user can neither upgrade nor uninstall nor untap. Every brew command that touches azd re-loads the cask definition from the untrusted tap and is blocked. There is no command in the banner, in azd --help, or in any error message that gets the user unstuck. They have to know about brew trust independently.
Root cause
Two independent changes converged:
- Homebrew added an "untrusted tap" guard for any tap outside
homebrew/core and homebrew/cask. The azure/azd tap (https://github.com/Azure/homebrew-azd) is now treated as untrusted by default. The guard fires on any operation that reads cask metadata — install, upgrade, and uninstall. So the guard also blocks the natural escape path.
azd is also distributed via homebrew/core as the azure-dev formula (Microsoft-maintained), with azd registered as an alias. But because the cask is also named azd, bare brew install azd resolves to the cask path first and trips the trust guard before the core alias ever gets a chance.
Net effect: every macOS user with azd installed via the cask path (which has been the historically recommended path, and what the banner still tells them to use) is wedged. The banner sends them in a circle with no working command.
Repro
- Have any
azd < 1.25.6 installed via the cask path (brew install --cask azure/azd/azd from the historical docs)
- Run any
azd command → banner appears
- Try any of:
brew upgrade azd, brew install azd, brew uninstall --cask --force azd, brew untap azure/azd → all fail with Refusing to load cask azure/azd/azd from untrusted tap azure/azd
Working manual fix (verified end-to-end)
Step 1 — get unstuck on 1.25.6 immediately (no brew trust needed):
brew install --formula azure-dev # installs 1.25.6 unlinked (cask's azd binary blocks the link)
brew link --overwrite azure-dev # azd 1.25.6 now active
azd version # 1.25.6
This works because brew link --overwrite is a formula operation and never reads cask metadata, so the trust guard doesn't fire. The cask is now dormant — azd runs from the formula.
Step 2 — clean up the leftover cask + tap so future brew upgrade (no args) doesn't keep failing. This step DOES require brew trust, because uninstalling the cask reads its metadata:
brew trust azure/azd # one-time trust grant
brew uninstall --cask azd
brew untap azure/azd
After step 2, the tap is gone, future brew install azd resolves cleanly to the homebrew/core formula via its azd alias, and brew upgrade Just Works.
Skipping step 2 leaves the user on 1.25.6 but with a Homebrew state that re-trips the trust guard on the next brew upgrade cycle.
Suggested fix
The current banner sends every cask-installed user — which is most users, since brew install --cask azure/azd/azd was the documented path — into a state where none of the commands they'd naturally try will work. The fact that even brew uninstall --cask azd and brew untap azure/azd are blocked makes this worse: there's no in-tooling escape hatch.
Two options for the banner:
Option A — recommend migrating to the homebrew/core formula (cleanest long-term; eliminates the third-party tap entirely; works whether the user is currently on cask or formula):
A new version of azd (1.25.6) is available.
To update, run:
brew install --formula azure-dev && brew link --overwrite azure-dev
For a full cleanup (recommended), then run:
brew trust azure/azd && brew uninstall --cask azd && brew untap azure/azd
Option B — detect install method, emit matching command, and never emit a cask command without the trust prerequisite:
- Formula install →
brew upgrade --formula azure-dev
- Cask install →
brew trust azure/azd && brew upgrade --cask azd
Either avoids the dead-end the current banner produces. Option A is preferable because it also fixes the underlying problem (third-party tap going forward) instead of just papering over it.
If the team wants to keep azure/homebrew-azd as the primary distribution channel, the azure/homebrew-azd README and the Homebrew tap landing page should also document the new brew trust azure/azd step prominently — Homebrew's tap-trust change broke installs from the tap, not just upgrades, so new users hitting the historical install command will also be stuck without it.
Environment
- macOS (Apple Silicon, Tahoe)
azd 1.25.4 → 1.25.6
- Homebrew current
- Originally installed via
brew install --cask azure/azd/azd (historically recommended path)
- Banner appears on every
azd invocation, including scripts that shell out to azd (e.g. azd env get-values inside other tools' bootstrap scripts)
What I saw
azd 1.25.4prints this update banner on every command:Following the suggested command fails:
Every obvious recovery a user might try also fails — including the ones that should let them escape the situation:
The user can neither upgrade nor uninstall nor untap. Every brew command that touches
azdre-loads the cask definition from the untrusted tap and is blocked. There is no command in the banner, inazd --help, or in any error message that gets the user unstuck. They have to know aboutbrew trustindependently.Root cause
Two independent changes converged:
homebrew/coreandhomebrew/cask. Theazure/azdtap (https://github.com/Azure/homebrew-azd) is now treated as untrusted by default. The guard fires on any operation that reads cask metadata — install, upgrade, and uninstall. So the guard also blocks the natural escape path.azdis also distributed via homebrew/core as theazure-devformula (Microsoft-maintained), withazdregistered as an alias. But because the cask is also namedazd, barebrew install azdresolves to the cask path first and trips the trust guard before the core alias ever gets a chance.Net effect: every macOS user with
azdinstalled via the cask path (which has been the historically recommended path, and what the banner still tells them to use) is wedged. The banner sends them in a circle with no working command.Repro
azd < 1.25.6installed via the cask path (brew install --cask azure/azd/azdfrom the historical docs)azdcommand → banner appearsbrew upgrade azd,brew install azd,brew uninstall --cask --force azd,brew untap azure/azd→ all fail withRefusing to load cask azure/azd/azd from untrusted tap azure/azdWorking manual fix (verified end-to-end)
Step 1 — get unstuck on 1.25.6 immediately (no
brew trustneeded):This works because
brew link --overwriteis a formula operation and never reads cask metadata, so the trust guard doesn't fire. The cask is now dormant —azdruns from the formula.Step 2 — clean up the leftover cask + tap so future
brew upgrade(no args) doesn't keep failing. This step DOES requirebrew trust, because uninstalling the cask reads its metadata:brew trust azure/azd # one-time trust grant brew uninstall --cask azd brew untap azure/azdAfter step 2, the tap is gone, future
brew install azdresolves cleanly to the homebrew/core formula via itsazdalias, andbrew upgradeJust Works.Skipping step 2 leaves the user on 1.25.6 but with a Homebrew state that re-trips the trust guard on the next
brew upgradecycle.Suggested fix
The current banner sends every cask-installed user — which is most users, since
brew install --cask azure/azd/azdwas the documented path — into a state where none of the commands they'd naturally try will work. The fact that evenbrew uninstall --cask azdandbrew untap azure/azdare blocked makes this worse: there's no in-tooling escape hatch.Two options for the banner:
Option A — recommend migrating to the homebrew/core formula (cleanest long-term; eliminates the third-party tap entirely; works whether the user is currently on cask or formula):
Option B — detect install method, emit matching command, and never emit a cask command without the trust prerequisite:
brew upgrade --formula azure-devbrew trust azure/azd && brew upgrade --cask azdEither avoids the dead-end the current banner produces. Option A is preferable because it also fixes the underlying problem (third-party tap going forward) instead of just papering over it.
If the team wants to keep
azure/homebrew-azdas the primary distribution channel, theazure/homebrew-azdREADME and the Homebrew tap landing page should also document the newbrew trust azure/azdstep prominently — Homebrew's tap-trust change broke installs from the tap, not just upgrades, so new users hitting the historical install command will also be stuck without it.Environment
azd1.25.4 → 1.25.6brew install --cask azure/azd/azd(historically recommended path)azdinvocation, including scripts that shell out to azd (e.g.azd env get-valuesinside other tools' bootstrap scripts)