When icu creates a canister (other than root), it passes (Principal, Principal) - so the canister knows what the root_id and the parent_id is.
What Im doing is passing another argument to the icu_start! macro, and this expands the init to add a third argument.
The code appears to work, the canister installs and this is the declaration within the candid
service : (principal, principal, principal) -> {
However, when the canister with this extra argument is created I get this error :
(
variant {
Err = variant {
IcuError = "call rejected: call rejected: 5 - Error from Canister lezmu-bh777-77774-qacia-cai: Canister called `ic0.trap` with message: \'Panicked at \'called `Result::unwrap()` on an `Err` value: Custom(Fail to decode argument 2 from table0 to principal\n\nCaused by:\n Subtyping error: principal)\', src/canisters/collection/src/lib.rs:23:1\'\nCanister Backtrace:\nic_cdk::api::trap\nic_cdk::printer::set_panic_hook::{{closure}}\nstd::panicking::rust_panic_with_hook\nstd::panicking::begin_panic_handler::{{closure}}\nstd::sys::backtrace::__rust_end_short_backtrace\n__rustc::rust_begin_unwind\ncore::panicking::panic_fmt\ncore::result::unwrap_failed\nic_cdk_executor::in_executor_context\nic_cdk::futures::in_executor_context\ncanister_init\n.\nConsider gracefully handling failures from this canister or altering the canister to handle exceptions. See documentation: https://internetcomputer.org/docs/current/references/execution-errors#trapped-explicitly"
}
},
)
How does encode_args((Principal, Principal)) work and encode_args((Principal, Principal, Principal)) not work?
This might be related to the fact that ((a, b), c) is not the same as (a, (b, c)) and there might be a difference between which of the two corresponds to (a, b, c) in candid and Rust.
Just thinking out loud: can you modify the interface? If yes, have you thought about using a struct? Reducing to one parameter “resolves” the issue, plus you could get better safety on which principal is the root_id and which one is the parent_id.
Yeah I had a struct before that was generic, but then I had issues making the candid show up as it needed a concrete version of that struct. That’s why I switched to multiple args.
But by the time it reaches init_async, it’s only getting the empty DIDL header [68, 73, 68, 76, 0, 0].
The encoded data is being lost somewhere between the calling canister and the
receiving one by calling init_async with take_raw_args().
We found the issue - we had an old call that was calling init_async() and we missed it. The SDK is working as intended!
That whole tuple thing with the trailing comma though, that’s just really hard to work with.
If there’s any way to add some error checking into the Encode!/encode_one/encode_args, just a sanity check that you’re, say, not sending a double encoded Vec or something, it would help.