Can't do cross-canister call in init function

I have an init function in my Rust canister, and I am trying to get access to randomness from the random beacon within that init function. I get the following error "ic0_call_new" cannot be executed in init mode.

I am trying to do this from the init function:

let call_result: Result<(Vec<u8>,), _> = ic_cdk::api::call::call(ic_cdk::export::Principal::management_canister(), "raw_rand", ()).await;

I’m pretty sure that that is a limitation. I ran across it in the IC code somewhere Init can’t do cross canister.

1 Like

Yes, I can confirm that is a limitiation, documented in the Interface Spec.

Motoko will actually statically reject actors that try to send messages from their initialisation code, but I guess the Rust library cannot or is not designed to enforce this.

2 Likes

If you look at the spec, the system functions have comments that use codes to indicate in which contexts they can be called (trapping on violation).

In particular, ic0_call_new cannot be called in mode I.

2 Likes

My experience is that you can’t use await in the init function, which means you can’t do cross-canister call and get the result in init function.

Could you elaborate on this limitation, please? Why does it work that way?

1 Like

My understanding is that the canister_init method is used to set up the initial invariants of the canister.
If you allowed messaging during canister_init, then another canister, or the canister itself, could call into the canister under construction, before its invariants have been established.

This is a well-known flaw with constructors in some OO languages, IIRC.

(NB: I didn’t design the System API and am just speculating on the rationale.)

3 Likes

Thanks a lot!
Then, I believe, it should be possible to introduce some kind of post_init lifecycle hook? That would be handy.

1 Like

I can definitely use await from the init function

1 Like

I don’t try it in Rust, but in motoko:

Stdout:

Stderr:
/Users/flyq/workspace/test/test_await/src/main1.mo:8.13-8.30: type error [M0038], misplaced await

source:

import Test2 "./main2";
import Principal "mo:base/Principal";
actor class Test1() {

    var a = 0;

    let b = await Test2.Test2; // line 8
...