astrid-runtime/astrid · error

signed channel names

Error message

signed channel names '{}', expected '{}'

What it means

validate_pointer checks a signed channel pointer (TOML metadata describing the latest release on an update channel). This error fires when the pointer's `channel` field does not match the channel the caller expected to fetch, e.g. fetching the stable channel but the file says `dev`. It guards against channel-confusion or a tampered/misrouted metadata file.

Solutions

  1. Fetch the channel metadata from the URL corresponding to the channel you intend (stable vs dev vs nightly) and retry
  2. Inspect the pointer's `channel` field in the signed TOML and confirm which channel it actually describes
  3. If you mirror feeds locally, regenerate/sync the mirror so each channel directory holds its own pointer
  4. Verify the signing/publication workflow writes the pointer under the matching channel name

Example fix

// before: fetching stable metadata from the nightly feed
let bytes = fetch("https://updates.example.com/nightly/channel.toml").await?;
let ptr = parse_channel(&bytes, UpdateChannel::Stable, now)?; // channel names 'nightly', expected 'stable'
// after
let bytes = fetch("https://updates.example.com/stable/channel.toml").await?;
let ptr = parse_channel(&bytes, UpdateChannel::Stable, now)?;
Defensive patterns

Strategy: validation

Validate before calling

fn channel_matches(pointer_toml: &str, expected: UpdateChannel) -> bool {
    pointer_toml.contains(&format!("channel = \"{}\"", expected.as_str()))
}
// call before parse_channel: channel_matches(&bytes_text, UpdateChannel::Stable)

Type guard

fn is_expected_channel(p: &ChannelPointer, expected: &UpdateChannel) -> bool {
    p.channel == expected.as_str()
}

Try / catch

match parse_channel(&bytes, expected, now) {
    Ok(ptr) => ptr,
    Err(e) if e.to_string().contains("signed channel names") => {
        eprintln!("fetched wrong channel feed: {e}");
        // re-fetch from the correct channel URL
        retry_with_correct_url(expected).await?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: parse_channel(bytes, expected_channel, now) or enforce_continuity is called with signed channel bytes whose `channel` field differs from `expected_channel.as_str()` (mismatch like "nightly" vs "stable"), typically because the wrong channel URL was fetched or the pointer was swapped.

Common situations: Misconfigured update-feed base URL pointing at another channel's directory; a CDN/redirect serving cached metadata from a different channel; hand-edited channel metadata; signing pipeline publishing to the wrong channel path.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/bdd9efcb87c7240d. Report an issue: GitHub.

Appendix: source

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

    let pointer: ChannelPointer =
        toml::from_str(text).context("signed channel metadata is invalid TOML")?;
    validate_pointer(&pointer, expected_channel, Some(now))?;
    Ok(pointer)
}

fn validate_pointer(
    pointer: &ChannelPointer,
    expected_channel: UpdateChannel,
    now: Option<DateTime<Utc>>,
) -> anyhow::Result<()> {
    ensure!(
        pointer.schema_version == 1
            && pointer.kind == "astrid-channel"
            && pointer.product == PRODUCT
            && pointer.repository == REPOSITORY,
        "signed channel identity is invalid"
    );
    ensure!(
        pointer.channel == expected_channel.as_str(),
        "signed channel names '{}', expected '{}'",
        pointer.channel,
        expected_channel.as_str()
    );
    ensure!(
        pointer.generation > 0,
        "signed channel generation must be positive"
    );
    let published = canonical_time(&pointer.published_at, "published-at")?;
    let expires = canonical_time(&pointer.expires_at, "expires-at")?;
    ensure!(expires > published, "signed channel lifetime is invalid");
    if let Some(now) = now {
        ensure!(now <= expires, "signed channel metadata has expired");
        let latest_reasonable_publication = now
            .checked_add_signed(chrono::Duration::seconds(MAX_FUTURE_SKEW_SECS))
            .context("channel publication skew overflowed the clock")?;
        ensure!(

View on GitHub (pinned to affd8760f4)