astrid-runtime/astrid · error

signed channel generation must be positive

Error message

signed channel generation must be positive

What it means

The signed channel pointer's `generation` counter must be strictly greater than 0. Generation is a monotonic counter used to order successive channel publications; a zero (or negative, if the type allows) value means the pointer was never properly initialized or was corrupted/forged, so enforce_continuity cannot order it against prior pointers.

Solutions

  1. Set `generation` in the channel TOML to a positive integer, one greater than the previous publication
  2. Re-run the official channel publishing workflow instead of hand-editing metadata
  3. If this appears on a fetched pointer, re-download: the upstream file may be truncated or corrupted
  4. For enforce_continuity callers, ensure the new generation is greater than the previously seen one and starts at 1

Example fix

// before (channel.toml)
generation = 0
// after
generation = 42
Defensive patterns

Strategy: validation

Validate before calling

fn generation_is_valid(p: &ChannelPointer) -> bool { p.generation > 0 }
// check after TOML parse, before use

Type guard

fn has_positive_generation(p: &ChannelPointer) -> bool {
    p.generation > 0
}

Try / catch

let ptr = parse_channel(&bytes, channel, now)
    .map_err(|e| if e.to_string().contains("generation must be positive") {
        anyhow!("channel metadata is uninitialized or corrupted: regenerate via the release workflow")
    } else { e })?;

Prevention

When it happens

Trigger: parse_channel or enforce_continuity receives pointer TOML with `generation = 0`, typically from a freshly fabricated metadata file, a template left unfilled by the release tooling, or corruption during editing.

Common situations: A release engineer scaffolding a new channel file and forgetting to bump/set the generation; a misbehaving publisher script writing the default value; a tampered pointer.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

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!(
            published <= latest_reasonable_publication,
            "signed channel published-at is unreasonably far in the future"
        );
    }
    let max_lifetime = match expected_channel {
        UpdateChannel::Stable => chrono::Duration::days(30),

View on GitHub (pinned to affd8760f4)