cube-js/cube · error

could not parse release metadata: {e}

Error message

could not parse release metadata: {e}

What it means

In `latest_release`, after the GitHub release lookup succeeds, the JSON body is deserialized into the `Release` struct. If the response body isn't valid JSON or doesn't match the `Release` shape, the reqwest JSON error is wrapped as `could not parse release metadata: {e}`. This is a response-shape failure, not a network failure (non-2xx is handled earlier).

Source

Thrown at rust/cube-cli/src/update.rs:79

/// Fetch the latest release metadata from the GitHub API.
pub async fn latest_release(http: &reqwest::Client) -> Result<Release> {
    let url = format!(
        "{}/repos/{}/releases/latest",
        release_api_base(),
        release_repo()
    );
    let res = http
        .get(&url)
        .header(reqwest::header::ACCEPT, "application/vnd.github+json")
        .timeout(Duration::from_secs(10))
        .send()
        .await?;
    if !res.status().is_success() {
        bail!("release lookup failed ({}) at {url}", res.status());
    }
    res.json::<Release>()
        .await
        .map_err(|e| anyhow!("could not parse release metadata: {e}"))
}

/// Order-compare two dotted versions numerically, segment by segment.
fn newer_than(candidate: &str, current: &str) -> bool {
    let parse = |v: &str| -> Vec<u64> {
        v.split(['.', '-'])
            .map_while(|s| s.parse::<u64>().ok())
            .collect()
    };
    let (a, b) = (parse(candidate), parse(current));
    if a.is_empty() || b.is_empty() {
        return candidate != current;
    }
    a > b
}

/// Outcome of the background release check.
#[derive(Debug, Clone, PartialEq, Eq)]

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Check the wrapped reqwest/serde message (`{e}`) for the exact field that failed to deserialize.
  2. Verify the release metadata URL returns the expected JSON (curl it and compare against the `Release` struct fields).
  3. Rule out proxies returning HTML with a 200 status.
  4. Update the CLI — an old `Release` struct may no longer match the current feed shape.

Example fix

// before (body mismatch)
could not parse release metadata: missing field `tag_name`
// after: verify feed
curl -s $RELEASE_URL | jq '.tag_name'
Defensive patterns

Strategy: try-catch

Validate before calling

let body = res.text().await?;
serde_json::from_str::<serde_json::Value>(&body)?; // pre-validate JSON shape
if body.get("tag_name").is_none() { /* abort before calling latest_release */ }

Try / catch

match latest_release(url).await {
    Err(e) if e.to_string().contains("could not parse release metadata") => {
        // inspect raw body / proxy behavior, fall back to current version
    }
    other => other?,
}

Prevention

When it happens

Trigger: `latest_release` fetches a release metadata URL that returns 2xx but with a body that fails `res.json::<Release>()`: HTML error pages behind proxies, changed/missing fields (e.g. tag name or assets) in the release JSON, or an empty body.

Common situations: Corporate proxy or captive portal returning 200 with HTML, GitHub API shape changes or a misconfigured update-manifest URL in self-hosted setups, running an old CLI against a renamed release feed.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/e6f51d9b6f6f1faf. Report an issue: GitHub.