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
- Set `generation` in the channel TOML to a positive integer, one greater than the previous publication
- Re-run the official channel publishing workflow instead of hand-editing metadata
- If this appears on a fetched pointer, re-download: the upstream file may be truncated or corrupted
- 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
- Always derive new generation from the previous pointer's generation + 1 in publishing scripts
- Never scaffold channel files by hand; use the official publisher
- Validate generation in CI before signing metadata
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
- capsule archive entry
- Cargo include table must contain a string path in
- must contain exactly targets
- release metadata identity is invalid
- nightly channel must point to an exact nightly prerelease
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)