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
- Check GitHub API rate limits (gh api rate_limit or curl the endpoint) and authenticate or wait before retrying
- curl the release URL and inspect the JSON for the tag_name field
- Fix the update-channel URL to point at the correct GitHub releases API endpoint
- 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
- Monitor GitHub API rate limits and use authenticated tokens for channel resolution
- Point update channels only at the official releases API endpoint
- Log the raw response body when metadata parsing fails
- Watch for GitHub API schema changes affecting release payloads
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
- models endpoint returned HTTP {}
- GitHub API returned {} fetching release {resolved_ref} of {o
- GitHub API error querying release tag {candidate} for {org}/
- GitHub API returned {} for {org}/{repo} latest release
- no GitHub releases found for {org}/{repo}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/e1006d4c45d80e7d.
Report an issue: GitHub.