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 ?

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

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;
            });

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.

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