Client Changes
Every pre-0.16 SQLite store is rejected. There is no migration path: delete the database and re-sync. Browser applications are handled automatically — the IndexedDB store detects the version bump and wipes itself on first open. In both cases any state that existed only locally is lost, including records for accounts not yet committed on-chain.
0.16 clients seal (encrypt) transaction inputs before submission. A 0.16 node rejects plaintext submissions and an older node rejects sealed ones, so the two cannot be mixed. Upgrade both.
Quick Fix
# CLI: the send subcommand was renamed
miden-client transfer -t <TARGET> -a 100::<FAUCET> -n private
// Rust: account updates are absolute patches now
let patch = tx_result.account_patch();
// Web: same split on the TypeScript side
const patch = txResult.accountPatch();
If you encounter errors, continue reading for detailed migration steps.
Summary
The client changes fall into four groups. The store break is the one that costs users data, and it is unavoidable. The fee and sealing changes are covered in Transaction Changes — they surface here as a new builder method and a node-version requirement. The rename churn (account_delta → account_patch, send → transfer, and friends) is mechanical. And a handful of silent behavioural changes — the call argument counting, the transaction summary display, notes.sendPrivate requiring a scan height — will not fail your build but will change what your application does.
(Store) Every pre-0.16 SQLite store must be recreated
Summary
The store schema changed substantially: account SMT forest tables were added, account IDs and all digest columns were retyped from hex TEXT to BLOB, a script_root index was added, and the migrations table was dropped in favour of a schema fingerprint.
Affected Code
A store written by miden-client 0.15.5 fails to open with:
Migration error: Attempt to migrate a database with a migration number that is too high
The changelog says opening a pre-0.16 database fails with SchemaHashMismatch. In practice a 0.15.5 store sits at user_version = 2, and because 0.16 defines only one migration the fingerprint check is skipped entirely — the failure surfaces from the migration layer instead. SchemaHashMismatch is only reached by a store at user_version = 1. Both paths fail; only the message differs.
Beyond the account ID retyping, the schema diff also shows the latest_account_assets and historical_account_assets column vault_key renamed to asset_id (following the protocol rename), a new unique index on tags(tag, source), and all digest columns retyped to BLOB — account_commitment, note_id, nullifier, script_root, recipient_digest, and storage keys and values.
Migration Steps
- Delete the store database and let the client recreate it, then re-sync.
- Export anything you need to keep before upgrading — private note files in particular.
- Browser applications need no action; the IndexedDB store resets itself when the client's minor version increases.
- If you implement a custom
Store, note thatinsert_block_headernow takes anodesargument,insert_partial_blockchain_nodeswas removed, and the newNoteFilter::ScriptRootsvariant makes existing exhaustive matches fail to compile.
(Rust) Account updates use AccountPatch
TransactionResult::account_delta() became account_patch(), and Account::apply_delta was replaced by construction from a patch. TransactionSummary::account_delta() is deliberately unchanged. This is covered in full under Account Changes.
One import detail specific to the client: in 0.15 AccountStorageDelta lived in miden_client::asset; the 0.16 replacement AccountStoragePatch lives in miden_client::account. The module moved as well as the name. StorageMapDelta and StorageSlotDelta were dropped from miden_client::asset alongside it, while AccountVaultDelta remains there.
(Rust) Fee conversion info on the transaction request
TransactionRequestBuilder::fee_conversion_info(info, salt) is new and required on fee-charging chains for AuthSingleSig and AuthMultisig accounts. See Transaction Changes for the full flow, including the mandatory salt argument that the changelog omits.
(Rust) Chain-anchored execution for multi-party signing
Client::chain_anchor_for_request and Client::execute_transaction_at are new, and they are not optional for any flow that derives a transaction summary on one client and executes it on another. Since the summary now binds the reference block, the parties must agree on that block or the collected signatures do not apply — see Transaction Changes for the full flow.
Two details specific to the client: ClientError gained a ChainAnchorError variant, so an exhaustive match over it no longer compiles; and both methods first appeared in 0.16.0-rc.2 and are included in the stable version pinned in Quick Upgrade.
(Rust) Fungible amounts use AssetAmount
Summary
The client surface switched from raw u64 to AssetAmount for fungible amounts. AccountReader::get_balance returns AssetAmount, and the token conversion helpers (tokens_to_base_units, base_units_to_tokens) and build_pswap_consume follow.
Migration Steps
- Wrap raw amounts with
AssetAmount, or unwrap with the provided accessor where you need au64. - Handle
TokenParseError::InvalidAmountwhere you parse user-supplied amounts.
(Rust) Auth and faucet re-exports changed
Summary
AuthMethod and AuthSingleSigAcl were removed, and the single fungible faucet factory split into auth-specific factories — see Assets, Vault & Faucet Changes. Note that the client re-exports only two of the six upstream factory functions; for the rest, depend on miden-standards directly.
The account policy components were also renamed, a change absent from the changelog and found by diffing the re-export lists:
- AllowlistOwnerControlled
+ AllowlistManager
- BlocklistOwnerControlled
+ BlocklistManager
(Rust) Note screening methods renamed
Summary
NoteScreener::can_consume became get_consumability, and can_consume_batch became get_batch_consumability. A new get_batch_consumability_for_account was added. Client::get_consumable_notes keeps its signature — passing a single account is now screened more efficiently, but nothing about the call changes.
The changelog justifies it by saying the methods now return a consumption status per account rather than a boolean. They never returned a boolean — the return type is identical in 0.15 and 0.16. Rename the call sites; do not change how you handle the result.
(Rust) Debug mode removed
DebugMode, ClientBuilder::in_debug_mode, Client::in_debug_mode, and the MIDEN_DEBUG environment variable were all removed. The VM replaced the flag-gated debug.* decorators with miden::core::debug procedures that print unconditionally, so there is nothing left to gate. See MASM Changes.
(Rust) Other library changes
StateSyncUpdateis immutable — construct withfrom_parts, read through accessors, and destructure withinto_parts.PartialBlockchainUpdates::insertlost its nodes argument, andextend_authentication_nodeswas added.miden_client::assembly::Librarywas removed. Usemiden_client::vm::Package. Note thatPackageis not new — it was already re-exported in 0.15; only theLibraryremoval is a 0.16 change.Client::fetch_all_private_noteswas removed, replaced by note transport syncing.TransactionRecordgained a private field, so struct literal construction no longer compiles.send_notesreads its payload from the advice provider and requires a payload-commitment script argument. Ascript_argpassed alongside aSendNotestemplate is ignored.AccountSmtForestis generic over its backend, and the root-staging API was removed.- Response verification moved into
VerifyingRpcClient. The built-in gRPC constructors now wrap the transport in it automatically, butClientBuilder::rpcdoes not — passing your ownNodeRpcClientcompiles and runs while silently losing response verification. Wrap it yourself withVerifyingRpcClient::new(..).
(Web) Package and API changes
Bump @miden-sdk/miden-sdk and @miden-sdk/react together — mixing 0.15 and 0.16 packages will not link against the shared WASM ABI.
| Change | Migration |
|---|---|
ClientOptions.debugMode removed; createClient* drops the trailing debugMode argument | Delete the option and the argument. |
accountDelta() → accountPatch(); AccountStorageDelta removed | Rename. TransactionSummary.accountDelta() is unchanged. |
TransactionSummary.salt() → userParams() | Rename; the value is now seven field elements. |
transactions.preview(..) returns only a summary while authorization is pending | Do not expect full transaction details from a preview. |
| A summary derived on one client no longer reproduces on another | Capture a ChainAnchor and pass it as the anchor option. See Transaction Changes. |
notes.sendPrivate requires scanAfterBlockNum; new notes.sendPrivateOutput | Pass a scan height. |
notes.fetchPrivate({ mode: "all" }) removed | Use note transport syncing. |
AccountComponent.createNetworkAuth → createNetworkAuthComponents | Rename; it now returns several components. |
FungibleAsset.withCallbacks(flag) removed | Set callbacks on the account at construction. |
| P2ID and P2IDE notes must carry at least one asset | Building an empty note now throws. |
| Production WASM strips MASM debug metadata | Expect less detail in production stack traces. |
Notes carrying a NetworkAccountTarget are priced via a foreign procedure invocation into the target | Behavioural; see the note below. |
Additive: notes.list({ scriptRoots }), NoteScript.networkAccountConfig(), NoteScript.feeSponsorship(), and compile.component({ namespace }).
First added in 0.16.0-rc.3 and included in the stable release: transactions.captureAnchor(request), an anchor option on preview / executeRequest / submit, the wasm-level chainAnchorForRequest / executeTransactionAt / executeForSummaryAt, and TransactionSummary.blockCommitment() / expirationDelta().
If you author MASM through the Web SDK, the language changes apply to you as well — @account_procedure annotations, mod declarations, and the new import syntax. See MASM Changes.
The NetworkAccountTarget foreign-procedure-invocation requirement is reported from the changelog. We were not able to locate the enforcing call site in source, so treat it as a lead rather than a confirmed behaviour.
(React) Send hooks relay through sendPrivateOutputNote
useSend, useTransaction, and useMultiSend now relay private note output via sendPrivateOutputNote, following the notes.sendPrivate change above. If you wrapped these hooks, re-check the relay path.
(React) useChainAnchor and usePreview
Both first appeared in 0.16.0-rc.3 and are included in the stable release; useTransaction().execute accepts an anchor alongside them. usePreview is the first summary surface in the React SDK — before it, verifying and co-signing a multisig proposal meant dropping to the WASM client.
If you build a multi-party signing flow, preview and execute against the anchoredRequest that useChainAnchor returns rather than the request you passed in. Re-resolving a request factory produces a different transaction, and any builder that creates an output note draws a fresh serial number, so the anchor would pin a request nobody executes. See Transaction Changes.
(CLI) send renamed to transfer
Summary
The send subcommand is now transfer. Nothing else changed — every flag, short form, and default is identical. send is not kept as an alias, so existing scripts fail with an unknown-subcommand error.
Affected Code
# Before (0.15)
miden-client send -s <SENDER> -t <TARGET> -a 100::<FAUCET> -n private
# After (0.16)
miden-client transfer -s <SENDER> -t <TARGET> -a 100::<FAUCET> -n private
Migration Steps
Replace miden-client send with miden-client transfer in scripts, aliases, and CI jobs. Change nothing else.
(CLI) account --with-code replaced by account --inspect
Summary
--with-code, which dumped the account code as one pretty-printed blob, is gone. account --inspect <ID>[:<PROCEDURE>] lists the procedures an account exposes, split into resolved procedures (name, signature, originating package) and unresolved ones listed by MAST root.
Affected Code
# Before (0.15)
miden-client account --show <ID> --with-code
# After (0.16)
miden-client account --inspect <ID> # list procedures
miden-client account --inspect <ID> --verbose # with MASM disassembly
miden-client account --inspect <ID>:receive_asset # a single procedure
miden-client account --inspect <ID> -p ./component.masp # resolve names from extra packages
Migration Steps
- Replace
account --show <ID> --with-codewithaccount --inspect <ID> --verbose. --inspectis mutually exclusive with--list,--show, and--default.--packageand--verboseboth require--inspect.- Expect
<unresolved>entries for procedures whose package the CLI cannot find; pass--packageto resolve them.
(CLI) call counts arguments in field elements
Summary
call validates argument count against the procedure's signature. In 0.15 it compared against the number of parameters; in 0.16 it compares against the total stack width in field elements. A procedure taking one Word now needs four --args values.
This change is not in the changelog.
Affected Code
# A procedure with signature `set_item(Word) -> ()`
# Before (0.15): one parameter, one argument
miden-client call <ID>:set_item -p component.masp --args 0x1234
# After (0.16): a Word is four felts wide
miden-client call <ID>:set_item -p component.masp --args <f0> <f1> <f2> <f3>
Migration Steps
- Re-check every scripted
callwhose procedure takes or returns anything wider than one field element. - Expand each wide argument into one value per field element, in signature order.
- Read the
Raw Signature:line the command prints — it is now the authoritative stack layout.
A mismatched count fails with a clear error rather than executing with a mis-shaped stack, so this one fails loudly.
(CLI) token_symbol_map.toml: id renamed to address
Summary
The per-symbol entry key changed from id to address. The value format is unchanged — it was already a bech32 address — so this is a pure key rename. A file still using id fails to parse rather than falling back.
Affected Code
# Before (0.15)
BTC = { id = "mlcl1qru2e5yvx40ndgqqqzusrryr0ucyd0uj", decimals = 8 }
# After (0.16)
BTC = { address = "mlcl1qru2e5yvx40ndgqqqzusrryr0ucyd0uj", decimals = 8 }
Migration Steps
- Rename
id =toaddress =on every entry. Leave the values alone. - The file lives in the
.midendirectory alongsidemiden-client.toml. If you have both a local and a global.midendirectory, update both.
(CLI) init writes a different package set
Summary
init now writes nine bundled .masp component packages instead of seven.
# Added in 0.16
basic-non-fungible-faucet.masp
auth/guarded-multisig-auth.masp
auth/network-account-auth.masp
# Removed in 0.16
auth/acl-auth.masp
The removal is the CLI-side consequence of dropping AuthSingleSigAcl, and it is the one most likely to break an existing setup. The changelog mentions only the additions.
Two error-reporting changes also landed: running init where a config already exists now names the configured network and points at clear-config, and an unparseable --remote-prover-endpoint is a hard error instead of being silently discarded.
(CLI) Other changes
--debugandMIDEN_DEBUGremoved. Passing--debugis now a usage error; settingMIDEN_DEBUGis silently ignored.- The pre-confirmation transaction summary shows absolute values, not deltas — including a column rename and
Nonce incremented by: NbecomingNew account nonce: N. This follows from theAccountPatchmove but changes what users read before approving a transaction. swapgained--payback-note-type <private|public>, defaulting toprivate(0.15 hardcoded private). Note thatpswapalready had this flag in 0.15 with the same default. The tag the command tells you to track also changed, from a swap-specific tag to an account-target tag derived from the sender's account ID.consume-notesgained--start-debug-adapter <ADDR>and--record <FILE>;execgained--record.exec --start-debug-adapteralready existed in 0.15. Both require a build with thedapfeature, which is not enabled by default.
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
Migration error: Attempt to migrate a database with a migration number that is too high | Pre-0.16 store | Delete and recreate the store. |
error: unrecognized subcommand 'send' | Renamed | Use transfer. |
error: unexpected argument '--with-code' | Removed | Use --inspect. |
Procedure '<name>' expects 4 value(s), got 1 | Arguments counted in field elements | Expand wide arguments. |
missing field 'address' parsing the token map | Key renamed | Rename id to address. |
error: unexpected argument '--debug' | Removed | Delete the flag. |
no method named account_delta on a transaction result | Renamed | Use account_patch(). |
| Node rejects a submission | Mixed client and node versions | Upgrade both to 0.16. |
A component package is missing after init | auth/acl-auth.masp was removed | Migrate off AuthSingleSigAcl. |