Kuberwastaken/claurst · error

no tag_name in GitHub API response

Error message

no tag_name in GitHub API response

What it means

fetch_latest_version parsed the GitHub releases/latest API response successfully, but the JSON had no string 'tag_name' field. The code uses get("tag_name").and_then(as_str).ok_or_else(anyhow!) to bail. GitHub guarantees tag_name on release objects, so this usually means the response was not the expected release payload (e.g. a rate-limit or error JSON body that still parsed).

Solutions

  1. Check GitHub API rate-limit headers (X-RateLimit-Remaining) and wait or authenticate with GITHUB_TOKEN.
  2. Print the raw response body to see what JSON was actually returned.
  3. Verify the releases URL points at api.github.com/repos/<owner>/<repo>/releases/latest.
  4. Check the GitHub API changelog for schema changes to the release object.

Example fix

// before
let tag = json.get("tag_name").and_then(|v| v.as_str()).ok_or_else(|| anyhow!("no tag_name in GitHub API response"))?;
// after
let tag = json.get("tag_name")
    .and_then(|v| v.as_str())
    .or_else(|| json.get("message").and_then(|m| m.as_str()))
    .ok_or_else(|| anyhow!("no tag_name in GitHub API response: {}", json))?;
Defensive patterns

Strategy: type-guard

Validate before calling

// validate response shape before treating it as a release
if json.get("tag_name").and_then(|v| v.as_str()).is_none() {
    eprintln!("unexpected GitHub response: {}", json);
}

Type guard

fn extract_tag(json: &serde_json::Value) -> Option<&str> {
    json.get("tag_name").and_then(|v| v.as_str())
}

Try / catch

// surface the full body when the shape is wrong
let tag = extract_tag(&json)
    .ok_or_else(|| anyhow!("no tag_name in GitHub API response: {}", json))?;

Prevention

When it happens

Trigger: GET to the GitHub releases endpoint returns 2xx but the JSON lacks tag_name: an error/rate-limit body, a redirect landing page, or a changed/empty response shape in run_upgrade's version check.

Common situations: GitHub API rate limiting returning a JSON error object with an unexpected status handling; API schema change; proxy returning alternate JSON; hitting a mirror of api.github.com.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/37d66d1209534cfb. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/cli/src/upgrade.rs:196

// ---------------------------------------------------------------------------
// GitHub API: latest version
// ---------------------------------------------------------------------------

async fn fetch_latest_version() -> Result<String> {
    let url = format!("https://api.github.com/repos/{}/releases/latest", REPO);
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(10))
        .user_agent(format!("claurst-upgrade/{}", env!("CARGO_PKG_VERSION")))
        .build()?;
    let resp = client.get(&url).send().await?;
    if !resp.status().is_success() {
        bail!("GitHub API returned {} for {}", resp.status(), url);
    }
    let json: serde_json::Value = resp.json().await?;
    let tag = json
        .get("tag_name")
        .and_then(|v| v.as_str())
        .ok_or_else(|| anyhow!("no tag_name in GitHub API response"))?;
    Ok(tag.trim_start_matches('v').to_string())
}

// ---------------------------------------------------------------------------
// Download
// ---------------------------------------------------------------------------

async fn download_to_file(url: &str, dest: &Path) -> Result<()> {
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(120))
        .user_agent(format!("claurst-upgrade/{}", env!("CARGO_PKG_VERSION")))
        .build()?;
    let resp = client.get(url).send().await?;
    if !resp.status().is_success() {
        bail!(
            "Download failed: HTTP {} for {}\n\
             Check that this version exists in the releases page.",
            resp.status(),

View on GitHub (pinned to b0637c97ec)