{"record":{"id":"bdd9efcb87c7240d","repo":"astrid-runtime/astrid","slug":"signed-channel-names-expected","errorCode":null,"errorMessage":"signed channel names '{}', expected '{}'","messagePattern":"signed channel names '(.+?)', expected '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/update_channel.rs","lineNumber":469,"sourceCode":"    let pointer: ChannelPointer =\n        toml::from_str(text).context(\"signed channel metadata is invalid TOML\")?;\n    validate_pointer(&pointer, expected_channel, Some(now))?;\n    Ok(pointer)\n}\n\nfn 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!(","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/update_channel.rs#L451-L487","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fetch the channel metadata from the URL corresponding to the channel you intend (stable vs dev vs nightly) and retry","Inspect the pointer's `channel` field in the signed TOML and confirm which channel it actually describes","If you mirror feeds locally, regenerate/sync the mirror so each channel directory holds its own pointer","Verify the signing/publication workflow writes the pointer under the matching channel name"],"exampleFix":"// before: fetching stable metadata from the nightly feed\nlet bytes = fetch(\"https://updates.example.com/nightly/channel.toml\").await?;\nlet ptr = parse_channel(&bytes, UpdateChannel::Stable, now)?; // channel names 'nightly', expected 'stable'\n// after\nlet bytes = fetch(\"https://updates.example.com/stable/channel.toml\").await?;\nlet ptr = parse_channel(&bytes, UpdateChannel::Stable, now)?;","handlingStrategy":"validation","validationCode":"fn channel_matches(pointer_toml: &str, expected: UpdateChannel) -> bool {\n    pointer_toml.contains(&format!(\"channel = \\\"{}\\\"\", expected.as_str()))\n}\n// call before parse_channel: channel_matches(&bytes_text, UpdateChannel::Stable)","typeGuard":"fn is_expected_channel(p: &ChannelPointer, expected: &UpdateChannel) -> bool {\n    p.channel == expected.as_str()\n}","tryCatchPattern":"match parse_channel(&bytes, expected, now) {\n    Ok(ptr) => ptr,\n    Err(e) if e.to_string().contains(\"signed channel names\") => {\n        eprintln!(\"fetched wrong channel feed: {e}\");\n        // re-fetch from the correct channel URL\n        retry_with_correct_url(expected).await?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Derive the metadata URL from the UpdateChannel enum instead of hardcoding per-channel paths","Never copy a channel.toml between channel directories","Log the pointer's channel field when a fetch succeeds so mismatches surface immediately","Use enforce_continuity in tests to catch cross-channel swaps in mirrors"],"tags":["validation","update-channel","config"],"backgroundTag":"invalid-argument-value","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"}