astrid-runtime/astrid · error

release has no tag_name

Error message

release has no tag_name

What it means

fetch_release_by_tag downloads the release metadata JSON within a size bound and then reads the tag_name field. If the JSON is valid but has no string tag_name field, the resolved actual tag cannot be compared against the requested tag, so this error is thrown. It indicates the endpoint returned something other than the expected GitHub-style release object.

Source

Thrown at crates/astrid-cli/src/commands/update_channel.rs:109

async fn fetch_release_by_tag(
    client: &reqwest::Client,
    owner: &str,
    repo: &str,
    tag: &str,
) -> anyhow::Result<serde_json::Value> {
    let encoded_tag: String = url::form_urlencoded::byte_serialize(tag.as_bytes()).collect();
    let url = format!(
        "{}/repos/{owner}/{repo}/releases/tags/{encoded_tag}",
        api_base()
    );
    let body =
        download_bounded(client, &url, MAX_RELEASE_METADATA_BYTES, "release metadata").await?;
    let json: serde_json::Value =
        serde_json::from_slice(&body).context("failed to parse release metadata")?;
    let actual_tag = json
        .get("tag_name")
        .and_then(|value| value.as_str())
        .ok_or_else(|| anyhow::anyhow!("release has no tag_name"))?;
    ensure!(
        actual_tag == tag,
        "release endpoint returned tag '{actual_tag}', expected '{tag}'"
    );
    Ok(json)
}

pub(super) async fn resolve_signed_channel(
    client: &reqwest::Client,
    owner: &str,
    repo: &str,
    channel: UpdateChannel,
    target: &str,
) -> anyhow::Result<ResolvedChannelRelease> {
    // One process owns channel acceptance through the final atomic pointer
    // commit. Without this lock, concurrent generations could interleave and
    // leave the lower pointer as the accepted rollback floor.
    let _lock = acquire_channel_lock(channel)?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Check GitHub API rate limits (gh api rate_limit or curl the endpoint) and authenticate or wait before retrying
  2. curl the release URL and inspect the JSON for the tag_name field
  3. Fix the update-channel URL to point at the correct GitHub releases API endpoint
  4. If a proxy is in use, ensure it forwards the upstream release JSON unmodified

Example fix

// before
url = "https://api.example.com/repos/org/repo/releases/tags/v1.2.3" // wrong shape
// after
url = "https://api.github.com/repos/org/repo/releases/tags/v1.2.3"
Defensive patterns

Strategy: validation

Validate before calling

let body: serde_json::Value = serde_json::from_slice(&meta)?;
if body.get("tag_name").and_then(|v| v.as_str()).is_none() {
    eprintln!("response is not a release object (rate limited or wrong endpoint?): {body}");
    return;
}

Type guard

fn has_string_field(v: &serde_json::Value, key: &str) -> bool {
    v.get(key).and_then(|x| x.as_str()).is_some()
}
let is_release = |v: &serde_json::Value| has_string_field(v, "tag_name");

Try / catch

match fetch_release_by_tag(&client, &tag).await {
    Ok(release) => apply(release),
    Err(e) if e.to_string().contains("tag_name") => {
        eprintln!("release endpoint returned an unexpected body — check rate limits and channel URL");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: resolve_signed_channel calling fetch_release_by_tag against an endpoint whose response JSON lacks a string tag_name (e.g. an API error object, rate-limit JSON body, HTML error page that happens to parse, or a changed API schema).

Common situations: GitHub API rate limiting returning a message-only JSON body; pointing the update channel at a proxy/mirror with a different response shape; GitHub API schema changes or wrong endpoint URL configured.

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 astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/e1006d4c45d80e7d. Report an issue: GitHub.