PocketIC Version 10.0.0: bootstrapping system canisters

PocketIC

We have released PocketIC server 10.0.0 and its compatible libraries:

The main new feature included in this release is support for bootstrapping system canisters transparently as part of PocketIC instance creation. The release also includes a full matrix of PocketIC server binaries for both linux/macOS and x86_64/arm64.

Changelog

Here’s an overview of the new features included in the latest PocketIC release and their use cases:

  • bootstrapping system canisters as part of PocketIC instance creation: a set of ICP features can be specified to be enabled during PocketIC instance creation by deploying system canisters implementing the features (the corresponding system canisters are not deployed if some option is not specified);

  • “nonmainnet” configuration: flags for ICP configuration options can be specified during PocketIC instance creation (“mainnet” configuration is used if some option is not specified).

For a complete list of changes, see the server changelog and the Rust library changelog.

Conclusion

Your feedback helps us improve PocketIC, so please let us know your thoughts and questions in this thread.

Thank you for providing feature requests and feedback on your PocketIC user experience!

7 Likes

Thanks for the release :raised_hands:

The argument of the endpoint /instances/ takes an additional optional field incomplete_state specifying if incomplete state (e.g., resulting from not deleting a PocketIC instance gracefully) is allowed.

What is the default value of incomplete_state used by PocketIC, I’m guessing false, and, if that’s a correct assumption, what are the drawbacks of enabling it?

Regarding icp_features, is there any documentation available on what each option does and which canisters are spun up by each option? For example, does icp_token include both the ledger and the index canister? Does sns spin up an example SNS project, or only the necessary canisters for creating and proposing projects? etc.

Is there a new option that needs to be set in order to deploy a custom CMC canister? I’m facing the following error when I’m bootstrapping it with PocketIC v10:

:warning: CLI Error: e [AgentError]: Call failed:
Canister: aaaaa-aa
Method: install_code (update)
“Request ID”: “57a9b8cb6f3826c87b1fd3ac11d9f2e91688d99736ebc33cae10f3f3b604d065”
“Error code”: “IC0505”
“Reject code”: “5”
“Reject message”: “Error from Canister rkp4c-7iaaa-aaaaa-aaaca-cai: Canister’s Wasm module is not valid: Wasm module has an invalid import section. Module imports function ‘mint_cycles’ from ‘ic0’ that is not exported by the runtime..\nIf you are running this canister in a test environment (e.g., dfx), make sure the test environment is up to date. Otherwise, this is likely an error with the compiler/CDK toolchain being used to build the canister. Please report the error to IC devs on the forum: https://forum.dfinity.org and include which language/CDK was used to create the canister.”

Note: I double-checked, and it seems the wasm.gz for the commit I’ve been using since May 2025 is still available to download, so the error is unlikely due to an empty wasm.

Incomplete state is indeed not enabled per default. The drawback of enabling incomplete state is that messages and their effects on canister state might be lost in an incomplete state.

I added documentation in this PR.

The error is due to using an old WASM that is no longer compatible with a recent replica. I’d recommend using the cycles_minting ICP feature to deploy CMC transparently during PocketIC instance creation.

1 Like

Apologies, I don’t get it. Could you try to rephrase, or is there any documentation about this feature?

Nice, thanks!

I upgraded my CMC commit to the latest deployed on mainnet, it resolved the issue. Thanks for the hint! :+1:

It’s likely that I’ll ultimately use the new icp_features, but one thing at a time :slightly_smiling_face:.

The feature was added to address this issue.

My expectation was that it’d be used internally by dfx so I didn’t plan to advertise it publicly here (and confuse people). But now that you’re interested in it, let me elaborate a bit on a concrete scenario showing why that feature might give unexpected results:

  • a PocketIC instance is created and configured to persists its state in a state directory;
  • a counter canister is deployed to the PocketIC instance;
  • the current value of the counter is 41;
  • a checkpoint is created and written to the state directory;
  • an update call is executed and the value of the counter becomes 42;
  • the PocketIC server is killed (no graceful shutdown);
  • a new PocketIC instance is created and configured to use the same state directory;
  • the value of the counter is 41 (although it was already observed to be 42).

The reason for the counter being 41 again is that the new PocketIC instance loads its state from the last checkpoint and all changes made between the last checkpoint and the (abrupt) kill are lost. (There are other “low-level” side-effects such as non-monotone time which result in crashes reported on the linked thread, but the one described above could actually be confusing to end-users which is why an option to enable “incomplete” state was introduced as opposed to silently adjusting time to avoid the reported crash.)

1 Like

Thanks a lot for the detailed explanation!! If I understand correctly, aside from a potential UX drawback, there aren’t really any technical issues with enabling this feature. Good to know then. I won’t enable it either right now, since I just released a version, but I wonder if, over time, this might become the default. Let’s see…