{"record":{"id":"53fb495ab5e62225","repo":"xai-org/grok-build","slug":"gh-release-download-failed-for-tag-from","errorCode":null,"errorMessage":"gh release download failed for {} tag {} from {}: {}","messagePattern":"gh release download failed for (.+?) tag (.+?) from (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-update/src/auto_update.rs","lineNumber":2439,"sourceCode":"        crate::version::GH_RELEASE_REPO,\n        \"--pattern\",\n        pattern,\n        \"--output\",\n        &dest.to_string_lossy(),\n        \"--clobber\",\n    ])\n    .stdin(Stdio::null())\n    .stdout(Stdio::null())\n    .stderr(Stdio::piped());\n    xai_grok_tools::util::detach_command(&mut cmd);\n    cmd.envs(xai_grok_tools::util::pager_env());\n    let output = cmd.output().await?;\n\n    pb.finish_and_clear();\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        anyhow::bail!(\n            \"gh release download failed for {} tag {} from {}: {}\",\n            pattern,\n            tag,\n            crate::version::GH_RELEASE_REPO,\n            stderr.trim()\n        );\n    }\n    Ok(())\n}\n\n/// Download and install grok from GitHub Releases (xai-org-shared/grok-build).\n///\n/// Uses `gh release download` to fetch the binary matching the current platform.\n/// This works anywhere the `gh` CLI is authenticated, without needing npm or\n/// internal network access.\nasync fn install_gh_release(target: Option<&str>) -> Result<()> {\n    let (os, arch) = detect_platform()?;\n    let platform = format!(\"{}-{}\", os, arch);","sourceCodeStart":2421,"sourceCodeEnd":2457,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-update/src/auto_update.rs#L2421-L2457","documentation":"This error wraps a failed `gh release download` subprocess invocation. The command ran (spawn succeeded) but exited non-zero; the message includes the release pattern, tag, the GH_RELEASE_REPO repository, and the trimmed stderr from the gh CLI so the developer can see gh's own diagnostic (auth errors, missing release, network failures).","triggerScenarios":"Calling the gh-release download helper (with a pattern, tag, and repo) when the `gh release download` process exits non-zero: tag does not exist, asset matching the pattern is missing, gh is not authenticated (no GH_TOKEN / `gh auth login`), gh CLI is outdated, or the network/DNS fails inside gh.","commonSituations":"Running the updater in CI without gh credentials (401/403 in stderr); requesting a tag that was deleted or not yet published; specifying an asset glob pattern that matches nothing; corporate proxy blocking gh; gh CLI not installed on PATH so an older/wrong binary is invoked.","solutions":["Read the stderr embedded in the message — it contains gh's specific reason (404, 403, 'release not found', etc.).","Run `gh auth status` and authenticate (gh auth login or set GH_TOKEN) if the stderr indicates auth failure.","Verify the tag exists: `gh release view <tag> -R <repo>`; if not, use a valid/current tag.","Check the asset pattern matches an actual release asset name.","Update gh (`gh upgrade` or reinstall) if the stderr shows unsupported flags or API changes; verify proxy settings if network errors appear."],"exampleFix":"// before: calling with a hardcoded stale tag\ngh_download(\"grok-cli-*\", \"v0.9.9\").await?;\n\n// after: resolve the latest tag first and surface gh's stderr\nlet tag = latest_release_tag().await?; // e.g. via gh api repos/:repo/releases/latest\nmatch gh_download(\"grok-cli-*\", &tag).await {\n    Err(e) => {\n        eprintln!(\"gh download failed for tag {tag}; check `gh auth status` and that the asset exists\");\n        return Err(e);\n    }\n    Ok(()) => {}\n}","handlingStrategy":"try-catch","validationCode":"// Preflight: gh installed, authenticated, and the tag exists\nlet auth = std::process::Command::new(\"gh\").args([\"auth\", \"status\"]).output()?;\nif !auth.status.success() {\n    anyhow::bail!(\"gh not authenticated; run `gh auth login` or set GH_TOKEN\");\n}\nlet view = std::process::Command::new(\"gh\")\n    .args([\"release\", \"view\", tag, \"-R\", repo])\n    .output()?;\nif !view.status.success() {\n    anyhow::bail!(\"release {tag} not found in {repo}\");\n}","typeGuard":"fn gh_succeeded(status: &std::process::ExitStatus) -> bool {\n    status.success()\n}","tryCatchPattern":"match gh_release_download(pattern, tag, repo).await {\n    Ok(()) => {}\n    Err(e) => {\n        let msg = e.to_string();\n        if msg.contains(\"403\") || msg.contains(\"authentication\") {\n            eprintln!(\"gh auth problem: run `gh auth login` or set GH_TOKEN\");\n        } else if msg.contains(\"not found\") || msg.contains(\"404\") {\n            eprintln!(\"tag/pattern {tag}/{pattern} does not exist in {repo}\");\n        } else {\n            return Err(e);\n        }\n    }\n}","preventionTips":["Ensure `gh` is installed and current on all machines/CI images that run the updater.","Provision GH_TOKEN in CI and rotate it before expiry.","Validate the tag and asset glob against `gh release view` before downloading.","Keep the embedded stderr in logs — it carries the actionable gh message."],"tags":["subprocess","github-cli","download","authentication"],"backgroundTag":"subprocess-nonzero-exit","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}