NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #5000 most downloaded on crates.io
Macros implementation of #[derive(CandidType)] for the Candid.
Last release 13 days ago
25 Sep 2026
Release timing varies
gaps range from 2 weeks to 4 months
Most releases are documented
notes for 31 of 42 stable releases
3 versions withdrawn
withdrawn after publishing
6 years old
45 releases · first in 2020
One column per quarter.
Patch release of candid / candid_derive, 0.10.36 → 0.10.37. No source changes — it dates the two decoder fixes already on master.
chore: Release candid 0.10.37 (#772)
Patch release of `candid` / `candid_derive`, 0.10.36 → 0.10.37. No
source changes — it dates the two decoder fixes already on `master`.
## Summary
- Bump `candid` and `candid_derive` 0.10.36 → 0.10.37, and the `=` pin
between them
- Date the `Unreleased` changelog entries as `2026-09-25` / `Candid
0.10.37`, covering:
+ Bounding the byte length of the type-table header, 64 KiB by default
and configurable with `set_max_header_len` (#770)
+ Bounding the size of a type named in a decoder diagnostic, so its
rendering no longer follows the type's own width and depth (#771)
- Refresh `Cargo.lock`, `rust/bench/Cargo.lock`, `tools/ui/Cargo.lock`
and `rust/candid/fuzz/Cargo.lock`
`candid_parser` is unchanged at 0.4.1; its dependency on `candid` is a
`0.10.16` floor, so it needs no bump.
The lockfile diffs are version bumps only — no dependency churn.
## All four lockfiles this time
The 0.10.36 release noted that `rust/candid/fuzz/Cargo.lock` was stale
at 0.10.34 and that all four lockfiles should move together as a
release-checklist step. This one does that, so `fuzz` goes 0.10.34 →
0.10.37.
`tools/ui` patches `candid` to the workspace path, so its lockfile pins
the path crate's version and has to move with the bump.
`candid-ui-release.yml` builds `didjs` there with `--locked` and
triggers on the date tag, so a stale lock would only fail at tag time,
after merge.
## Test plan
- [x] `cargo check -p candid -p candid_derive -p candid_parser`
- [x] `cargo test -p candid --features all` — all suites pass
- [x] `cd tools/ui && cargo build --target wasm32-unknown-unknown
--profile canister --package didjs --locked` — the release workflow's
exact command, succeeds
- [x] `cd rust/candid/fuzz && cargo check`
- [ ] Reviewer to confirm release scope and changelog date
## After merge
1. Tag `2026-09-25` on `master` — this is what `candid-ui-release.yml`
triggers on to publish the `candid_ui` canister wasm
2. Run the **Crates Publish** workflow (`workflow_dispatch`) with the
`candid` input checked, which publishes `candid_derive` then `candid`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
DecoderConfig::set_max_header_len. Headers over the bound, far above any realistic interface, are now rejected; the value section is unaffected, and set_max_type_len still separately bounds the number of type-table entries.set_full_error_message(true) selects; ordinary mismatches are unchanged and still name both types.2026-09-25: chore: Release candid 0.10.37 (#772) Latest
Latest
Compare
Scope the decode fast paths of a map to their own half of an entry, so a map entry's key and value each decode under their own declared type. deserial
deserialize_map derives a big-integer fast path from the map's value type and a text fast path from its key type; each previously stayed active for the whole entry. The big-integer path is now cleared for the duration of the key and restored for the value, the text path is cleared for the duration of the value, and the value's expected and wire types are re-established on every entry. Each half of an entry therefore goes through its own type's entry point, keeping its own encoding (SLEB128 for int, LEB128 for nat) and its own subtype check, for every combination of key and value type — including a value whose type shares an encoding with the key's, such as blob against text. The wire format is unchanged, and entries whose key and value types agree decode identically.opt. The queue is only mutated at the top level, so it is now shared rather than copied and the snapshot is a refcount bump. Skipping many present optional arguments is no longer superlinear in the argument count; the decode result is unchanged.Bound the allocation when reading a length-prefixed byte field in the type-table header. A byte vector (a future type's payload, or a service method's
Fix decoding a vec of fixed-width primitives into newtype elements (e.g. struct EventIndex(u32)), which failed with a spurious subtyping error since 0
vec of fixed-width primitives into newtype elements (e.g. struct EventIndex(u32)), which failed with a spurious subtyping error since 0.10.27. The bulk decode fast path fed each element through serde's value deserializers, which do not implement deserialize_newtype_struct; they now go through a wrapper that forwards it, as the main deserializer does. Nested newtypes are unwrapped recursively.is_human_readable() reporting true for elements of a vec of fixed-width primitives, also since 0.10.27. The bulk decode fast path inherited serde's default from the same value deserializers, so a Deserialize impl that branches on it took its human-readable path inside a vec while taking the binary path everywhere else, silently decoding to a different value with no error. It now reports false for the whole decoder, as candid is a binary format.Migrated from the deprecated `binread` crate to its successor binrw. The types in the candid::binary_parser module (Header, PrincipalBytes, Len, BoolV…
Breaking changes:
Migrated from the deprecated binread crate to its successor binrw. The types in the candid::binary_parser module (Header, PrincipalBytes, Len, BoolValue) now implement binrw::BinRead instead of binread::BinRead, and From<binread::Error> for candid::Error is replaced by From<binrw::Error>.
Released as a patch rather than a minor bump because the affected surface is limited to those trait impls. binary_parser is an internal wire-format parsing module that is pub only incidentally — it is used nowhere outside candid's own deserializer, and it is now #[doc(hidden)] to say so. Code is affected only if it depends on binread directly and names these impls; the wire format, decoder error messages, byte offsets, type layouts, and all function signatures are unchanged, so the worst case is a compile error rather than a behaviour change.
Non-breaking changes:
binrw migration, which drops binread's debug_template codegen: up to 37% fewer instructions on variant-heavy payloads (multi_arg −36.6%, result_variant −10.3%, large_variant −9.5%, subtype_decode −8.0%, double_option −7.0%), with no regressions.syn 1.x dependency tree that binread_derive pinned (along with rustversion).binrw::Error variant now degrades to a label-less error instead of panicking, since binrw::Error is #[non_exhaustive] and decoding runs on untrusted input.A service reference now decodes where a principal is expected: service is a subtype of principal (spec addition: service <: principal, modelled analog
principal is expected: service <actortype> is a subtype of principal (spec addition: service <: principal, modelled analogously to nat <: int). The subtype checker and the deserializer accept a service reference at type principal; the two share an identical wire encoding, so the coercion is the identity on the reference. The reverse (a principal at a service type) remains rejected.Encode and decode large Nat/Int values in linear time. Values beyond the u64/i64 fast path were previously processed one LEB128/SLEB128 group at a tim
Nat/Int values in linear time. Values beyond the u64/i64 fast path were previously processed one LEB128/SLEB128 group at a time, shifting the whole bignum on every byte (O(n²) in the encoded length); they now build the value in a single O(n) pass.Add pretty::sep_enclose and sep_enclose_space: list/tuple pretty-printing combinators that separate items and enclose them in delimiters, emitting a t
pretty::utils::sep_enclose and sep_enclose_space: list/tuple pretty-printing combinators that separate items and enclose them in delimiters, emitting a trailing separator on multi-line layouts.TypeEnv::to_sorted_iter() to iterate bindings in a deterministic, key-sorted order.Fix text_fast_path leakage between nested maps: an inner map with non-text keys would fail with a "Type mismatch" error when enclosed in an outer map
text_fast_path leakage between nested maps: an inner map with non-text keys would fail with a "Type mismatch" error when enclosed in an outer map with text keysFix LEB128/SLEB128 fast path silently truncating Nat/Int values near the u64/i64 boundary during decoding
Nat/Int values near the u64/i64 boundary during decodingInt::decode truncating large magnitudes due to fast-path leakageAdd subtype_check_all() to collect all subtype errors in one pass (previously stopped at the first)
subtype_check_all() to collect all subtype errors in one pass (previously stopped at the first)Incompatibility type and format_report() for structured, hierarchical error reportingFix decoding failure when a trailing argument is a primitive vector
Preserve Rust doc comments on exported Candid types, record fields, and variant members when generating .did files via #[derive(CandidType)]
.did files via #[derive(CandidType)]Implement DataSize for Principal, enabling Principal as an element type in BoundedVec
DataSize for Principal, enabling Principal as an element type in BoundedVecAdd BoundedVec type to candid::bounded_vec for bounding a vector by number of elements, total data size, and per-element data size during deserializat
BoundedVec type to candid::types::bounded_vec for bounding a vector by number of elements, total data size, and per-element data size during deserializationUse target_family = "wasm" for platform detection to cover both wasm32 and wasm64; skip recursion check on wasm (sandboxed), use stack-based check on
target_family = "wasm" for platform detection to cover both wasm32 and wasm64; skip recursion check on wasm (sandboxed), use stack-based check on native platforms and a conservative depth limit on other niche platformsTypeEnv::is_empty, trace_type, rec_find_type, as_func, as_service), value type annotation (IDLValue::annotate_type), subtype checking (subtype_(), equal()), and all deserializer methods (deserialize_option, deserialize_seq, deserialize_map, deserialize_tuple, deserialize_tuple_struct, deserialize_struct, deserialize_enum)RecursionDepth with DepthGuard) for automatic depth management, eliminating manual increment/decrement operationsAdd max_type_len to DecoderConfig to configure the type table size limit (default: 10,000) during binary parsing.
max_type_len to DecoderConfig to configure the type table size limit (default: 10,000) during binary parsing.fix: subtyping and coercion rules for optional types
reserved at any context do not coerce into values of type nullnull in the textual format are decoded into a default valueFixes a compatibility issue with serde v1.0.220 and later.
serde v1.0.220 and later.Implement serde::Serialize and PartialOrd, Ord, Hash for the Reserved type.
serde::Serialize and PartialOrd, Ord, Hash for the Reserved type.Fixes a regression in pretty printing when concatenating an empty list of documents
Makes the warning message for the special opt subtyping rule more explicit in the candid::subtype::subtype and candid::subtype::subtype_with_config fu
candid::types::subtype::subtype and candid::types::subtype::subtype_with_config functions.pp_label_raw in pretty::candid module.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Upgrade candid_parser dependency to v0.4.0.
curl --proto ' =https ' --tlsv1.2 -LsSf https://github.com/dfinity/candid/releases/download/didc-v0.6.2/didc-installer.sh | sh
didc check now reports all incompatible changes at once, grouped by method, instead of stopping at the first error
didc check now reports all incompatible changes at once, grouped by method, instead of stopping at the first errorNothing published for this version
The didc test subcommand has been removed.
didc test subcommand has been removed.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Escape the method names of a service type in the Rust binding. A Candid method name is an arbitrary text value, but pp_ty_service emitted it raw betwe
pp_ty_service emitted it raw between the quotes of a Rust string literal inside candid::define_service!. A name containing " therefore closed the literal and the macro invocation, and the rest of the name was compiled as Rust — a .did file could inject arbitrary items into the bindings generated from it, and from there into the consumer's binary. Names are now escaped with escape_debug, as pp_function and the #[serde(rename)] attributes already were. The value seen by define_service! is unchanged, and names that are ordinary identifiers generate byte-identical output.Parse and preserve named function arguments and results. The AST now carries argument names so consumers (e.g. binding generators) can emit meaningful
syntax::IDLArgType { typ: IDLType, name: Option<String> } with IDLArgType::new / IDLArgType::new_with_name. Purely numeric names are normalized to None.syntax::FuncType::{args, rets}, syntax::IDLType::ClassT, syntax::IDLTypes::args, and syntax::IDLInitArgs::args now hold Vec<IDLArgType> instead of Vec<IDLType>.(from : principal)).candid::types::Function, so the candid crate is unaffected.Changed imports generated by candid_parser::typescript::compile from @dfinity/* to @icp-sdk/core/*
candid_parser::bindings::typescript::compile from @dfinity/* to @icp-sdk/core/*fix: escape */ to prevent premature JS doc comment termination
*/ to prevent premature JS doc comment terminationRust binding: Sets service_name based on top level name config
service_name based on top level name configdidc v0.5, some identifiers started to be renamed. E.g. struct field amount_e8s was renamed to amount_e_8_s.
Now, field name like amount_e8s won't be renamed.to_identifier_case() in rust/candid_parser/src/bindings/rust/identifier.rs for more details.fix: ignore inline comments or separated by newlines
The candid_parser::types module has been renamed to candid_parser::syntax.
Breaking changes:
candid_parser::types module has been renamed to candid_parser::syntax.Non-breaking changes:
Supports collecting line comments as doc comments in the following cases:
// This is a valid doc comment for the service
service : {
greet : (text) -> (text);
}
service : {
// This is a valid doc comment for greet
greet : (text) -> (text);
}
// This is a valid doc comment for type A
type A = record {
my_field : text;
};
type A = record {
// This is a valid doc comment for my_field
my_field : text;
};
type B = record {
// This is a valid doc comment for nat element
nat;
text;
}
type C = variant {
// This is a valid doc comment for my_variant_field
my_variant_field : nat;
};
Adds the IDLMergedProg struct, used to collect the syntax types when parsing Candid declarations.
Supports reflecting doc comments from Candid declarations to the generated bindings. To enable this feature, we had to change the following:
candid_parser::bindings::motoko::compile function now takes an additional &IDLMergedProg parameter.candid_parser::bindings::rust::compile function now takes an additional &IDLMergedProg parameter.candid_parser::bindings::typescript::compile function now takes an additional &IDLMergedProg parameter.candid::pretty::syntax module has been added. It exposes the pretty_print function, which is used to pretty print the IDLMergedProg struct. The behavior is similar to the already existing candid::pretty::candid::compile function, but uses the syntax types instead of the candid types.Supports reflecting doc comments from Rust canister methods to the Candid generated bindings. Example:
/// Doc comment for greet,
/// even on multiple lines
#[candid_method(query)]
fn greet(name: &str) -> String {
format!("Hello, {name}!")
}
The generated Candid bindings will then look like this:
service : {
// Doc comment for greet,
// even on multiple lines
greet : (text) -> (text);
}
To support this feature, hhe following have been added:
candid::pretty::candid::DocComments struct, which is used to collect doc comments from Rust canister methods, in the candid_derive::export_service macro.candid::pretty::candid::compile_with_docs function, which takes a &DocComments parameter.Nothing published for this version
Add import service in parser to allow merging services.
import service in parser to allow merging services.Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →