I just started playing around locally with performing inter-canister calls in parallel from a canister to the management canister, and ran into the following error.
(This error is one long line, but I’m inserting newline characters to make it easier to read)
May 23 05:21:29.136
WARN s:utaii-kuahc-dtn2h-q52ef-kl77v-yozyo-pppml-dxhtm-u6zo5-ifzxe-jae/
n:lihjb-4jgo7-q3rph-633jm-sfszg-g2sov-6ppfr-u2r5e-rxhi2-ewgts-7qe/
ic_execution_environment/scheduler
At Round 170526 @ time 2022-05-23 05:21:28.403547 UTC,
canister t6rzw-2iaaa-aaaaa-aaama-cai has invalid state after execution.
Invariants check failed with err:
Invariant broken: Canister t6rzw-2iaaa-aaaaa-aaama-cai:
Number of call contexts (3) is different than the accumulated number
of reservations and responses (4),
messaging: {"round":170526,"canister_id":null,"message_id":null}
My setup is the following:
I have one main canister, and two child canisters. If I attempt to stop both child canisters in parallel, the call succeeds and stops both canisters, but I receive this WARN + invalid state after execution error which makes me worry about any side effects.
For reference, the main canister is the t6rzw-2iaaa-aaaaa-aaama-cai complaining about inconsistent state that you are seeing in the error message.
Here is the jist of what I’m doing to execute the stop canister requests in parallel from the main canister.
To perform parallel execution, the main canister calls the code below and is first executing each of the asynchronous calls in into the executingStopCanisters
buffer, and then I’m collecting/awaiting the results of those asynchronous calls in the next round into the collectingStoppedCanisters
buffer.
The CA.stopCanister
method is just a refactored version of the stop_canister method
public func stopAllCanisters(canisterPrincipals: [Principal]): async [Text] {
let executingStopCanisters = Buffer.init<async Text>();
for (principal in canisterPrincipals.vals()) {
Buffer.add<async Text>(executingStopCanisters, CA.stopCanister(principal));
};
let collectingStoppedCanisters = Buffer.init<Text>();
var i = 0;
label l loop {
if (i >= executingStopCanisters.count) break l;
Buffer.add(collectingStoppedCanisters, await executingStopCanisters.elems[i]);
i += 1;
};
Debug.print("all stops complete");
Buffer.toArray(collectingStoppedCanisters);
};
Is this a serious error? Should I be concerned about any side effects to the main canister making these calls?