Install_code actor class leads to error "empty input" and "too few arguments"

I’ve got a main canister (“manager”) that generates actor class canisters (“data”). In other words, each users of my web app get a canister.

I try to implement the install_code function to be able to upgrade these canisters that are generated on the fly or at least for now, implement a proof of concept of such process.

I have implement it as following:

  1. Instantiate my manager actor with agent-js in a NodeJS script using my private key and actor principal (Code)

  2. Read the wasm file that has been generated with dfx and sent it to my main canister as a blob (Code)

  3. In the main canister, in Motoko, declare a function (that still needs to be access protected but that’s another question) that iterate on each canisters (Code and Code)

  4. In a Motoko utility, effectively call install_code with the Blob data (Code)

When I call my script, I can confirm that the function is effectively triggered and that the user canister is most probably called too (as I get another Principal as the one of my manager in the console output) but, I get the following error anyway:

Error: Call was rejected:
Request ID: 0b96b73711842469a7772d…
Reject code: 4
Reject text: Canister 4wnqn-…-cai trapped explicitly: IDL error: empty input. Expected Candid-encoded argument, but received a zero-length argument

Any idea what am I missing or what is wrong in my implementation ?

2 Likes

Is there a call that you are sending with an empty argument? try sendiing these bytes for the arg: [68, 73, 68, 76, 0, 0] .

see this and and this

1 Like

Thanks. It seems it helped but, landed now on another error :crazy_face:

Reject code: 4
Reject text: Canister 4wnqn-…-cai trapped explicitly: IDL error: too few arguments P

I tried following in which both canister_id and wasm_module are values loaded locally and passed to my main canister.

await ic.install_code({
                arg = [68, 73, 68, 76, 0, 0];
                wasm_module = wasmModule;
                mode = #upgrade;
                canister_id = canisterId;
            });
1 Like

Looks like maybe your canister-init function, or your post-upgrade function in your canister takes some candid-parameters. If so, create those candid-parameters, serialize them into the bytes, and put those bytes as the value for the ‘arg’ field.

2 Likes

Oh interesting, those parameters respectively the owner of the canister you mean?

actor class DataBucket(owner: Types.UserId) = this {

source / ic.rocks

Took me more than a night of sleep :wink:.

Yes indeed @levi was correct, it needed a candid-parameter to update the code of the canister because my canister constructor takes a parameter, the user principal.

That solved this question but then I had to encode the parameters. This was solved today in my following question: Encode Principal to Candid arguments - #10 by peterparker

2 Likes