dfinity / dfinity/pocketic

encode_args encodes multiple arguments as single record instead of separate arguments

Open
#52 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
No language data
Stars
35
Forks
6
Avg merge
9m
Merged PRs (30d)
1

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the candid::encode_args and Encode! reproduction described in the issue, then trace how PocketIC's update_call receives and forwards the encoded bytes. Verify the behavior against the dfx canister call example and determine where tuple arguments become a single record. Done means multi-argument calls decode successfully in PocketIC like they do on the local IC replica, with regression coverage for the shown create_user case.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.