multica-ai/multica · error

brew upgrade failed: %w

Error message

brew upgrade failed: %w

What it means

UpdateViaBrew shells out to `brew upgrade multica-ai/tap/multica` and wraps any non-zero exit with 'brew upgrade failed: %w'. The wrapped error is an *exec.ExitError plus the captured CombinedOutput is returned alongside it. This is the self-update path used when the running binary is detected as a Homebrew install (IsBrewInstall).

Source

Thrown at server/internal/cli/update.go:335

func GetBrewPrefix() string {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, "brew", "--prefix")
	cmd.WaitDelay = 2 * time.Second
	out, err := cmd.Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

// UpdateViaBrew runs `brew upgrade multica-ai/tap/multica`.
// Returns the combined output and any error.
func UpdateViaBrew() (string, error) {
	cmd := exec.Command("brew", "upgrade", "multica-ai/tap/multica")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return string(out), fmt.Errorf("brew upgrade failed: %w", err)
	}
	return string(out), nil
}

func updateDownloadTimeoutOrDefault(timeout time.Duration) time.Duration {
	if timeout <= 0 {
		return DefaultUpdateDownloadTimeout
	}
	return timeout
}

// fetchURLBytes does a GET with the given timeout and returns the response
// body in full. Used for the checksum manifest (tiny) and the release
// archive (single-digit MB). The checksum verification path requires buffered
// bytes so streaming would just push the buffer into the caller anyway.
func fetchURLBytes(url string, timeout time.Duration) ([]byte, error) {
	client := &http.Client{Timeout: updateDownloadTimeoutOrDefault(timeout)}
	resp, err := client.Get(url)

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Read the returned output string — brew prints the actual reason (unknown formula, permission, network) to stderr and it is included in the first return value.
  2. Verify Homebrew is installed and on PATH: `which brew` (exec.LookPath("brew") in code).
  3. Fix ownership of the brew prefix (e.g. `sudo chown -R $(whoami) /opt/homebrew`) or rerun the update in a shell where brew works.
  4. Repair the tap: `brew tap multica-ai/tap` then retry the upgrade.
  5. If brew is fundamentally unavailable, fall back to the download-based updater (UpdateViaDownload) instead of the brew path.

Example fix

// before
out, err := cli.UpdateViaBrew()
if err != nil {
    log.Fatal(err) // loses brew's own diagnostics
}

// after
out, err := cli.UpdateViaBrew()
if err != nil {
    log.Printf("brew update failed: %v\nbrew output:\n%s", err, out)
    if _, lookErr := exec.LookPath("brew"); lookErr != nil {
        log.Printf("falling back to download-based update")
        out, err = cli.UpdateViaDownload(targetVersion)
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

if _, err := exec.LookPath("brew"); err != nil {
    // brew unavailable; do not attempt UpdateViaBrew
}
if !cli.IsBrewInstall() {
    // not a brew-managed binary; use UpdateViaDownload instead
}

Type guard

func isExitError(err error) bool {
    var ee *exec.ExitError
    return errors.As(err, &ee)
}

Try / catch

out, err := cli.UpdateViaBrew()
if err != nil {
    log.Printf("brew update failed: %v\noutput: %s", err, out)
    if !isExitError(err) {
        return err // brew missing/launch failure, not a brew-level failure
    }
    out, err = cli.UpdateViaDownload(latest)
}

Prevention

When it happens

Trigger: Running the CLI update command on a machine where Homebrew is not installed or not on PATH; the tap multica-ai/tap no longer exists or was renamed; the formula is already up to date combined with a brew quirk; brew lacking write permission to its prefix (sudo-owned /opt/homebrew or /usr/local); network failure reaching github.com while brew fetches the bottle.

Common situations: CI runners with minimal images that lack brew; a user installed via the download path but a brew prefix string accidentally matches MatchKnownBrewPrefix; macOS System Integrity/permission prompts after a macOS upgrade; an offline or firewalled environment.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/12b430e6106e55df. Report an issue: GitHub.