encode_args encodes multiple arguments as single record instead of separate arguments
When using encode_args((arg1, arg2, arg3, ...)) in PocketIC tests to call canister methods with multiple arguments, the macro encodes the tuple as a single Candid record (table0) instead of encoding each argument separately. This causes deserialization failures in the receiving canister.
Environment PocketIC version: 10.0.0 Candid version: 0.10.20 ic-cdk version: 0.18 Expected Behavior Multiple arguments should be encoded as separate Candid arguments, matching the behavior of the real IC replica and dfx canister call.
Actual Behavior encode_args((arg1, arg2, arg3, ...)) encodes the tuple as a single record argument, causing:
Fail to decode argument 0 from table0 to <expected_type> Caused by: Subtyping error: Type mismatch Reproduction Canister method:
rust #[update] fn create_user( user_type_str: String, currency_str: String, email: String, first_name: String, last_name: String, principal_id: Option<String>, phone_number: Option<String>, ) -> Result<User, String> { ... } PocketIC test:
rust use candid::encode_args;
let result = pic.update_call( canister_id, Principal::anonymous(), "create_user", encode_args(( "User".to_string(), "UGX".to_string(), "[email protected]".to_string(), "John".to_string(), "Doe".to_string(), None::<String>, Some("+256700123456".to_string()), )).unwrap(), ); Error:
Panicked at 'called Result::unwrap() on an Err value: Custom(Fail to decode argument 0 from table0 to text
Caused by:
Subtyping error: text)'
Verification
The SAME code works perfectly on local IC replica:
bash
dfx canister call data_canister create_user
'("User", "UGX", "[email protected]", "John", "Doe", null, opt "+256700123456")'
✅ Returns: Ok(User { ... })
Workarounds Attempted ❌ Using Encode! macro: Encode!(&arg1, &arg2, ...).unwrap() - still encodes as record ❌ Using ic_cdk::call - deprecated and has same issue ❌ Passing struct instead - causes enum serialization issues Impact This makes it impossible to write PocketIC integration tests for canisters with multi-argument methods, forcing developers to:
Use local IC replica for all testing (much slower) Artificially limit APIs to single-argument methods Skip integration tests Expected Fix encode_args should encode tuples as separate Candid arguments (not a single record), matching real IC behavior.