Skip to content

fix(cli): do not panic on proposals with an unrecognised action - #2127

Merged
pietrodimarco-dfinity merged 1 commit into
mainfrom
pmarco/fix-proposal-action-unwrap
Aug 17, 2026
Merged

fix(cli): do not panic on proposals with an unrecognised action#2127
pietrodimarco-dfinity merged 1 commit into
mainfrom
pmarco/fix-proposal-action-unwrap

Conversation

@pietrodimarco-dfinity

Copy link
Copy Markdown
Contributor

What is broken

Every dre proposals filter and dre proposals list invocation currently panics against mainnet:

$ dre --nns-urls https://ic0.app/ proposals filter --topic ic-os-version-deployment --limit 1000
2026-08-17T09:14:23.286Z INFO  dre > Running version 0.7.8-3ea01f9d362ee989945154326b2dd9732e1aacd5

thread 'main' panicked at rs/cli/src/commands/proposals/mod.rs:94:44:
called `Option::unwrap()` on a `None` value

It reproduces at --limit 5, --limit 100, and with no topic filter at all — the offending proposal is the newest one in the topic, so nothing narrows past it.

Root cause

Line 94 was payload: match proposal.action.unwrap(). Candid decodes a variant it cannot resolve in an opt field into None rather than failing, so any action added to the governance canister after a given dre release makes proposal.action None for that release — and unwrap() then kills the process.

The trigger is NNS proposal 143574, "Set the very first standard engine replica version to e3d101b2.", submitted 2026-08-14T16:37:42Z and still open. Its action is the native UpdateStandardEngineReplicaVersion variant (note action_nns_function: null — it is not an ExecuteNnsFunction like everything else in that topic), and ic-nns-governance-api as pinned in Cargo.lock (rev = abf88f22) has no such variant.

Impact

dfinity/dre-airflow's rollout_ic_os_to_mainnet_subnets DAG shells out to dre proposals filter to decide whether a subnet update proposal already exists. The NNS subnet (tdb26) step of rollout manual__2026-08-11T09:28:45+00:00 has therefore failed on every retry since 07:00 UTC on 2026-08-17 — batch_30.create_proposal_if_none_exists is stuck in up_for_retry, and the two downstream sensors (WaitForProposalAcceptance, has_proposal_executed) go through the same call, so they would fail too.

The fix

Both call sites already handle a failed conversion gracefully — filter logs the error and skips the proposal, list falls back to serialising the raw ProposalInfo. The panic was the only thing turning one unrecognised action into a total outage.

  • A None action now falls back to the canister's self_describing_action (which exists precisely to be understood without the schema of a specific proposal type), or to an empty payload when the canister did not send one. The proposal keeps its id, title, topic and status in listings instead of vanishing from them.
  • The remaining unwrap()s in the same conversion return errors instead, on the same principle: a malformed proposal should cost that one proposal, not the whole command.

Most of the diff is the re-indentation from wrapping the existing arms in Some(action) => match action { … }git diff -w shows the ~20 real lines.

Verification

Three regression tests in rs/cli/src/commands/proposals/mod.rs cover an unrecognised action with and without a self_describing_action, and the malformed-ProposalInfo paths.

Built from this branch and run against mainnet:

$ dre --nns-urls https://ic0.app/ proposals filter --topic ic-os-version-deployment --limit 1000
# exits 0; proposal 143574 is listed with an empty payload, the rest decode as before

The empty payload is compatible with the Airflow consumer, which filters on r["payload"].get("subnet_id").

Follow-up (not in this PR)

Bumping the pinned ic-nns-governance-api would let dre decode UpdateStandardEngineReplicaVersion properly rather than just tolerating it. This PR is deliberately limited to stopping the crash, since a mainnet rollout is blocked on it.

🤖 Generated with Claude Code

`dre proposals filter` and `dre proposals list` abort outright when the
governance canister returns a proposal whose action this build of `dre`
does not know about:

    thread 'main' panicked at rs/cli/src/commands/proposals/mod.rs:94:44:
    called `Option::unwrap()` on a `None` value

Candid decodes a variant it cannot resolve in an `opt` field into `None`,
so every action added to governance after a given `dre` release turns
`proposal.action` into `None` for that release. NNS proposal 143574
("Set the very first standard engine replica version to e3d101b2.",
action `UpdateStandardEngineReplicaVersion`) did exactly that when it was
submitted on 2026-08-14, and because it is the newest proposal in the
`ic-os-version-deployment` topic, *every* `dre proposals filter` call has
panicked since — at any `--limit`, and with no topic filter at all.

That includes the calls the mainnet rollout DAG uses to decide whether a
subnet update proposal already exists, so the NNS subnet (tdb26) step of
rollout `manual__2026-08-11T09:28:45+00:00` has been failing on every
retry since 07:00 UTC on 2026-08-17.

Both call sites already degrade gracefully when the conversion returns
`Err` — `filter` logs the error and skips the proposal, `list` falls back
to serialising the raw `ProposalInfo` — so the panic was the only thing
turning one unrecognised action into a total outage.

Handle a `None` action by falling back to the canister's
`self_describing_action`, which exists precisely to be understood without
the schema of a specific proposal type, or to an empty payload when the
canister did not send one. The proposal then still appears in listings
with its id, title, topic and status intact instead of disappearing. The
remaining `unwrap()`s in the same conversion become errors for the same
reason: a malformed proposal should cost that one proposal, not the whole
command.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pietrodimarco-dfinity
pietrodimarco-dfinity requested a review from a team as a code owner August 17, 2026 09:51
@pietrodimarco-dfinity
pietrodimarco-dfinity enabled auto-merge (squash) August 17, 2026 10:00
@pietrodimarco-dfinity
pietrodimarco-dfinity merged commit 9f97391 into main Aug 17, 2026
8 checks passed
@pietrodimarco-dfinity
pietrodimarco-dfinity deleted the pmarco/fix-proposal-action-unwrap branch August 17, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants