{"record":{"id":"cf3e84fe878e3bff","repo":"astrid-runtime/astrid","slug":"signed-channel-generation-must-be-positive","errorCode":null,"errorMessage":"signed channel generation must be positive","messagePattern":"signed channel generation must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/update_channel.rs","lineNumber":475,"sourceCode":"fn validate_pointer(\n    pointer: &ChannelPointer,\n    expected_channel: UpdateChannel,\n    now: Option<DateTime<Utc>>,\n) -> anyhow::Result<()> {\n    ensure!(\n        pointer.schema_version == 1\n            && pointer.kind == \"astrid-channel\"\n            && pointer.product == PRODUCT\n            && pointer.repository == REPOSITORY,\n        \"signed channel identity is invalid\"\n    );\n    ensure!(\n        pointer.channel == expected_channel.as_str(),\n        \"signed channel names '{}', expected '{}'\",\n        pointer.channel,\n        expected_channel.as_str()\n    );\n    ensure!(\n        pointer.generation > 0,\n        \"signed channel generation must be positive\"\n    );\n    let published = canonical_time(&pointer.published_at, \"published-at\")?;\n    let expires = canonical_time(&pointer.expires_at, \"expires-at\")?;\n    ensure!(expires > published, \"signed channel lifetime is invalid\");\n    if let Some(now) = now {\n        ensure!(now <= expires, \"signed channel metadata has expired\");\n        let latest_reasonable_publication = now\n            .checked_add_signed(chrono::Duration::seconds(MAX_FUTURE_SKEW_SECS))\n            .context(\"channel publication skew overflowed the clock\")?;\n        ensure!(\n            published <= latest_reasonable_publication,\n            \"signed channel published-at is unreasonably far in the future\"\n        );\n    }\n    let max_lifetime = match expected_channel {\n        UpdateChannel::Stable => chrono::Duration::days(30),","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/update_channel.rs#L457-L493","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (channel.toml)\ngeneration = 0\n// after\ngeneration = 42","handlingStrategy":"validation","validationCode":"fn generation_is_valid(p: &ChannelPointer) -> bool { p.generation > 0 }\n// check after TOML parse, before use","typeGuard":"fn has_positive_generation(p: &ChannelPointer) -> bool {\n    p.generation > 0\n}","tryCatchPattern":"let ptr = parse_channel(&bytes, channel, now)\n    .map_err(|e| if e.to_string().contains(\"generation must be positive\") {\n        anyhow!(\"channel metadata is uninitialized or corrupted: regenerate via the release workflow\")\n    } else { e })?;","preventionTips":["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"],"tags":["validation","update-channel","toml"],"backgroundTag":"value-out-of-range","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}