astrid-runtime/astrid · error

stable and dev channels must point to canonical releases

Error message

stable and dev channels must point to canonical releases

What it means

Stable and dev channel pointers must reference canonical releases: the version must have an empty pre-release segment and empty build metadata. A pointer on these channels to something like `1.2.3-rc.1` or `1.2.3+build5` is rejected because stable/dev distributions must come from final, unadorned versions.

Source

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

        );
    }
    let max_lifetime = match expected_channel {
        UpdateChannel::Stable => chrono::Duration::days(30),
        UpdateChannel::Dev => chrono::Duration::days(7),
        UpdateChannel::Nightly => chrono::Duration::days(2),
    };
    ensure!(
        expires.signed_duration_since(published) <= max_lifetime,
        "signed channel lifetime exceeds the maximum for its channel"
    );
    let version = canonical_version(&pointer.release.version)?;
    let nightly_commit = nightly_source_commit(&version);
    match expected_channel {
        UpdateChannel::Nightly => ensure!(
            nightly_commit.is_some() && version.build.is_empty(),
            "nightly channel must point to an exact nightly prerelease"
        ),
        UpdateChannel::Stable | UpdateChannel::Dev => ensure!(
            version.pre.is_empty() && version.build.is_empty(),
            "stable and dev channels must point to canonical releases"
        ),
    }
    ensure!(
        pointer.release.tag == format!("v{version}"),
        "signed channel release tag does not match its version"
    );
    ensure!(
        is_commit(&pointer.release.source_commit),
        "signed channel source commit is invalid"
    );
    if let Some(commit) = nightly_commit {
        ensure!(
            commit == pointer.release.source_commit,
            "nightly channel version does not embed its source commit"
        );
    }

View on GitHub (pinned to affd8760f4)

Solutions

  1. Point the stable/dev channel at the final release version (e.g. `1.2.3`, no suffix) and republish
  2. Publish pre-releases under the nightly channel, or don't publish them as channel pointers at all
  3. Strip build metadata when promoting a tested build to stable, then cut a proper release tag
  4. Re-run the release workflow for the correct channel

Example fix

// before (dev channel.toml)
version = "1.2.3-rc.1"
// after
version = "1.2.3"
Defensive patterns

Strategy: validation

Validate before calling

fn stable_or_dev_version_ok(v: &semver::Version) -> bool {
    v.pre.is_empty() && v.build.is_empty()
}

Type guard

fn is_canonical_release(version: &str) -> bool {
    semver::Version::parse(version)
        .map(|v| v.pre.is_empty() && v.build.is_empty())
        .unwrap_or(false)
}

Try / catch

match parse_channel(&bytes, UpdateChannel::Stable, now) {
    Err(e) if e.to_string().contains("canonical releases") => {
        anyhow::bail!("stable channel must not point at a prerelease; publish the final version")
    }
    other => other?,
}

Prevention

When it happens

Trigger: parse_channel or enforce_continuity with expected_channel = Stable or Dev and a version containing `version.pre` (e.g. `2.0.0-rc.1`, `0.5.0-nightly.20260909.deadbeef`) or non-empty `version.build`.

Common situations: Copying a nightly pointer into the dev channel during testing; publishing an RC to the stable channel; a release script forgetting to strip build metadata after the final tag.

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/bc2001a3d109c31e. Report an issue: GitHub.