Skip to content

Work around the Anchor 2.0.0-rc.1 IDL enum bug, and fix the one failure that was ours - #132

Merged
mikemaccana merged 1 commit into
mainfrom
claude/idl-enum-workaround
Aug 20, 2026
Merged

Work around the Anchor 2.0.0-rc.1 IDL enum bug, and fix the one failure that was ours#132
mikemaccana merged 1 commit into
mainfrom
claude/idl-enum-workaround

Conversation

@mikemaccana

Copy link
Copy Markdown
Collaborator

Nine projects fail anchor build. Eight are one upstream bug, already fixed upstream but unreleased; the ninth was ours and is fixed here.

The upstream bug

anchor-derive-accounts 2.0.0-rc.1 emits enum type definitions with the JSON key "fields" where anchor-lang-idl-spec requires "variants", so anchor build cannot deserialize the IDL it just generated:

Error: missing field `variants` at line 1 column N

One shared helper causes it. type_def_header_parts in the derive crate's src/idl.rs hardcodes the key:

type_def_obj.insert("type".into(), json!({ "kind": kind_name, "fields": [FIELD_MARKER] }));

Both emitters call it: build_struct_type_def_emission with kind_name = "struct", which is correct, and build_enum_type_def_emission with kind_name = "enum", which is not. The spec is IdlTypeDefTy::Enum { variants: Vec<IdlEnumVariant> }, with no serde(default), so deserialization hard-fails.

Reproduced end to end with a twenty-line program containing #[derive(IdlType)] pub enum Side { Bid, Ask }. The emitted JSON is:

"types":[{"name":"Side","type":{"fields":[{"name":"Bid"},{"name":"Ask"}],"kind":"enum"}}]

The variant objects are correct; only the container key is wrong. Unit variants are enough, tuple variants fail identically, and the failure is invisible to cargo check, cargo clippy and cargo test because idl-build is a feature only anchor idl build turns on.

Fixed upstream in otter-sec/anchor#4947 (commit 51323eb, 19 Aug 2026), which adds exactly the missing branch:

let entries_key = if kind_name == "enum" { "variants" } else { "fields" };

That is not in the v2.0.0-rc.1 tag (12 Aug) and is not on crates.io.

Why the workaround is --no-idl and not a dependency patch

Patching only the derive crate to the fixed commit was tried and does not resolve: anchor-derive-accounts on anchor-next requires solana-address 2.7.0, and every program here pins >=2.6, <2.7 because anchor-lang 2.0.0-rc.1 is built against wincode 0.5 while solana-address 2.7 moved to 0.6. Cargo fails with a version conflict on solana-address. The comment in anchor.yml records this so nobody retries it.

Skipping IDL generation costs nothing today. None of the eight consumes a generated IDL: no idls/ directory, no declare_program! in any Rust source. The program is still compiled to a .so and its tests still run, which is what the workflow is actually checking.

The workflow block is marked TEMPORARY WORKAROUND, says to delete it once a release after 2.0.0-rc.1 ships, and links the upstream PR.

The one that was ours

finance/vault-strategy was failing for an unrelated reason:

error[E0277]: `mock_swap_router::AssetRate` has no IDL type information

It has BorshAccount<AssetRate> fields whose type is declared in mock-swap-router, and #[account] only generates the IDL glue when the declaring crate has its own idl-build feature enabled. vault-strategy's idl-build was ["anchor-lang/idl-build"] and never forwarded. It now forwards to mock-swap-router/idl-build, with a comment saying why it is required rather than optional.

Verified locally with anchor idl build: that error is gone. It is not in the skip list, so CI will exercise its IDL generation for real.

Still outstanding, not addressed here

finance/order-book carries impl anchor_lang::IdlBuild for OrderTreeRoot {} at ordertree.rs:37 for a trait v2 removed. It is behind #[cfg(feature = "idl-build")], so nothing compiles it while that project skips IDL generation, but it is dead code that will need the v2 equivalent when the skip is lifted.

basics/pyth is in the skip list rather than fixed because fixing it properly runs into the same upstream bug: its vendored PriceUpdateV2 needs #[derive(IdlType)], which requires its verification_level: VerificationLevel field's enum to be an IDL type too.


Generated by Claude Code

…output

TEMPORARY. Delete the block in anchor.yml when a release after 2.0.0-rc.1
ships; the upstream fix is already merged.

anchor-derive-accounts 2.0.0-rc.1 emits enum type definitions with the JSON
key "fields" where anchor-lang-idl-spec requires "variants", so `anchor build`
cannot deserialize the IDL it just generated:

    Error: missing field `variants` at line 1 column N

The defect is one shared helper: `type_def_header_parts` in
anchor-derive-accounts' `src/idl.rs` hardcodes "fields" and is called by both
the struct emitter (kind_name = "struct", correct) and the enum emitter
(kind_name = "enum", wrong). A two-variant enum reproduces it.

Fixed upstream in otter-sec/anchor#4947, unreleased
at the time of writing. Patching only the derive crate to that commit does not
work: it requires solana-address 2.7, and these programs pin `>=2.6, <2.7`
because anchor-lang 2.0.0-rc.1 is built against wincode 0.5 while
solana-address 2.7 moved to 0.6.

Eight projects have an enum reachable from their IDL and hit it. None of them
consumes a generated IDL, so `--no-idl` costs nothing today: the program is
still compiled and its tests still run.

vault-strategy was failing for an unrelated and genuine reason, fixed here
rather than skipped: it has `BorshAccount<AssetRate>` fields whose type is
declared in mock-swap-router, and `#[account]` only generates the IDL glue
when the declaring crate has its own `idl-build` feature enabled. Its
`idl-build` now forwards to `mock-swap-router/idl-build`. Verified locally
with `anchor idl build`: the "has no IDL type information" error is gone.
@mikemaccana
mikemaccana merged commit a9245b5 into main Aug 20, 2026
27 of 41 checks passed
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