Skip to content

encode_args encodes multiple arguments as single record instead of separate arguments #52

@dicolasi

Description

@dicolasi

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,
phone_number: Option,
) -> 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(),
"test@example.com".to_string(),
"John".to_string(),
"Doe".to_string(),
None::,
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", "test@example.com", "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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions