Summary:
When using ic_cdk::api::call::reject
I can’t get the canister to return a reject code of 4
, i.e. CANISTER_REJECT
. I expect ic_cdk::api::call::reject
to trap like ic_cdk::api::trap and return that code immediately, but instead execution continues and as a result I can only return a 5
i.e. CANISTER_ERROR
.
Additional Details:
I’m trying to return a reject code of 4 (CANISTER_REJECT)
from a canister but it doesn’t seem possible. I’ve implemented the following canister with a method that just calls reject:
lib.rs
#[ic_cdk_macros::update]
async fn method() -> () {
ic_cdk::api::call::reject("Custom message...")
}
I expect that when called this would return a reject code of 4
and the “Custom message…” string that I passed in. Instead, when running dfx canister call my_canister method
I get the following:
Error: The Replica returned an error: code 5, message: “Canister ryjl3-tyaaa-aaaaa-aaaba-cai violated contract: ic0.msg_reply_data_append: the call is already replied”
I believe that what’s happening is that ic_cdk::api::call::reject
responds with a reject, but then execution continues, so when the method runs to completion it also attempts to send ()
the return value of this method.
I asked about this in discord and someone suggested that reject might only work from within inspect_message
. However, according to the IC Interface Spec, reject can be called from updates, queries, or reply/reject callbacks:
ic0.msg_reject : (src : i32, size : i32) → (); // U Q Ry Rt
And when trying this as shown in the following canister it doesn’t solve the problem:
#[ic_cdk_macros::update]
async fn method() -> String {
"Custom Message".to_string()
}
#[ic_cdk_macros::inspect_message]
async fn inspect_message() {
ic_cdk::api::call::reject("From Inspect Message...")
}
Calling this from dfx results in:
Error: The replica returned an HTTP Error: Http Error: status 500 Internal Server Error, content type “”, content: Requested canister failed to process the message acceptance request
Additionally I’ve tried calling this canister in a cross-canister call in case there was a difference between dfx call
and a cross-canister call. However when using ic_cdk::api::call::reject_code
to check the return code, I still only get a 5 (CANISTER_ERROR
) not a 4.
Am I misunderstanding how to use ic_cdk::api::call::reject
or is its implementation incorrect?