multica-ai/multica · error

fetch release metadata: %w

Error message

fetch release metadata: %w

What it means

fetchReleaseByTag queries the GitHub releases API for the normalized tag; failure is wrapped as 'fetch release metadata: %w'. This is the first network hop of the download-based updater, so network errors, GitHub rate limits (HTTP 403 with an API error body), 404 for a nonexistent tag, and timeouts all appear here.

Source

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

	return UpdateViaDownloadWithTimeout(targetVersion, DefaultUpdateDownloadTimeout)
}

// UpdateViaDownloadWithTimeout downloads the latest release binary with a caller-selected timeout.
func UpdateViaDownloadWithTimeout(targetVersion string, downloadTimeout time.Duration) (string, error) {
	// Determine current binary path.
	exePath, err := selfexec.Resolve()
	if err != nil {
		return "", fmt.Errorf("resolve executable path: %w", err)
	}
	exePath, err = filepath.EvalSymlinks(exePath)
	if err != nil {
		return "", fmt.Errorf("resolve symlink: %w", err)
	}

	tag := normalizeReleaseTag(targetVersion)
	release, err := fetchReleaseByTag(tag)
	if err != nil {
		return "", fmt.Errorf("fetch release metadata: %w", err)
	}
	asset, err := findReleaseAsset(release.Assets, tag, runtime.GOOS, runtime.GOARCH)
	if err != nil {
		return "", err
	}
	manifestAsset, err := findChecksumManifestAsset(release.Assets)
	if err != nil {
		return "", err
	}
	downloadURL := asset.BrowserDownloadURL
	assetName := asset.Name

	// Pull the checksum manifest first so a release that is half-published
	// (archives uploaded but checksums.txt not yet) fails before we eat the
	// archive's bandwidth.
	timeout := updateDownloadTimeoutOrDefault(downloadTimeout)
	manifestData, err := fetchURLBytes(manifestAsset.BrowserDownloadURL, timeout)
	if err != nil {

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Confirm the tag exists: `gh release view <tag>` or open https://github.com/multica-ai/multica/releases/tag/<tag>.
  2. For rate limiting, add an Authorization header/token to the API request or reduce poll frequency.
  3. For network failures, verify connectivity to api.github.com and retry — the poller retries on its next tick.
  4. Pass an empty targetVersion only if the code path supports fetching latest; otherwise use a real released tag.

Example fix

null
Defensive patterns

Strategy: retry

Type guard

func isGitHubAPIError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "fetch release metadata")
}

Try / catch

out, err := cli.UpdateViaDownload(ver)
if err != nil && isGitHubAPIError(err) {
    // network/rate-limit: retry on the next poll tick with backoff
    return retryLater(err)
}

Prevention

When it happens

Trigger: Calling UpdateViaDownload with a version whose tag does not exist on GitHub; unauthenticated API access beyond 60 req/h per IP; DNS/proxy failure; the API returning a non-200 that fetchReleaseByTag converts to an error.

Common situations: Fleets of machines polling for updates from one IP hitting the rate limit; corporate proxies blocking api.github.com; a typo'd or unpushed targetVersion passed from config.

Related errors


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