{"record":{"id":"ea3c6dfe721d333b","repo":"multica-ai/multica","slug":"fetch-release-metadata-w","errorCode":null,"errorMessage":"fetch release metadata: %w","messagePattern":"fetch release metadata: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update.go","lineNumber":385,"sourceCode":"\treturn UpdateViaDownloadWithTimeout(targetVersion, DefaultUpdateDownloadTimeout)\n}\n\n// UpdateViaDownloadWithTimeout downloads the latest release binary with a caller-selected timeout.\nfunc UpdateViaDownloadWithTimeout(targetVersion string, downloadTimeout time.Duration) (string, error) {\n\t// Determine current binary path.\n\texePath, err := selfexec.Resolve()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve executable path: %w\", err)\n\t}\n\texePath, err = filepath.EvalSymlinks(exePath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve symlink: %w\", err)\n\t}\n\n\ttag := normalizeReleaseTag(targetVersion)\n\trelease, err := fetchReleaseByTag(tag)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"fetch release metadata: %w\", err)\n\t}\n\tasset, err := findReleaseAsset(release.Assets, tag, runtime.GOOS, runtime.GOARCH)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tmanifestAsset, err := findChecksumManifestAsset(release.Assets)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdownloadURL := asset.BrowserDownloadURL\n\tassetName := asset.Name\n\n\t// Pull the checksum manifest first so a release that is half-published\n\t// (archives uploaded but checksums.txt not yet) fails before we eat the\n\t// archive's bandwidth.\n\ttimeout := updateDownloadTimeoutOrDefault(downloadTimeout)\n\tmanifestData, err := fetchURLBytes(manifestAsset.BrowserDownloadURL, timeout)\n\tif err != nil {","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update.go#L367-L403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Confirm the tag exists: `gh release view <tag>` or open https://github.com/multica-ai/multica/releases/tag/<tag>.","For rate limiting, add an Authorization header/token to the API request or reduce poll frequency.","For network failures, verify connectivity to api.github.com and retry — the poller retries on its next tick.","Pass an empty targetVersion only if the code path supports fetching latest; otherwise use a real released tag."],"exampleFix":"null","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isGitHubAPIError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"fetch release metadata\")\n}","tryCatchPattern":"out, err := cli.UpdateViaDownload(ver)\nif err != nil && isGitHubAPIError(err) {\n    // network/rate-limit: retry on the next poll tick with backoff\n    return retryLater(err)\n}","preventionTips":["Verify the tag exists before targeting it","Authenticate GitHub API calls in fleet deployments to raise rate limits","Space update polls minutes apart, not seconds"],"tags":["github","api","network","rate-limit"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}