Failed to decode wasm module

When trying to upgrade a canister with a new wasm module programmatically through the admin canister I am getting this error.

(
  "Error from Canister dfztg-4aaaa-aaaak-qijzq-cai: Canister\'s Wasm module is not valid: Failed to decode wasm module: unsupported canister module format",
)

Here is the code block that is is attempting to make the upgrade

try {
      status := "stopping";
      await Canister.CanisterUtils().stopCanister(canister);
      status := "installing";
      await Canister.CanisterUtils().installCode(canister, arg, wasm);
      status := "starting";
      await Canister.CanisterUtils().startCanister(canister);
      status := "success";
  } catch (e) {
      await Canister.CanisterUtils().startCanister(canister);
      status := Error.message(e);
  };
},
public func stopCanister(canisterId: Principal): async () {
    await ic.stop_canister({ canister_id = canisterId });
};

public func startCanister(canisterId: Principal): async () {
    await ic.start_canister({ canister_id = canisterId });
};

public func installCode(canisterId: Principal, arg: Blob, wasmModule: Blob): async() {
    await ic.install_code({
        arg = arg;
        wasm_module = wasmModule;
        mode = #upgrade;
        canister_id = canisterId;
    });
};

DFX Version 0.20.1

The canister that is attempting to make the upgrade is a controller of the canister that it is trying to upgrade. I also tried deleting and creating a new canister but the error persist.

The logic I am using above has worked for multiple other projects so I’m not sure what the issue is

1 Like

The error comes from here. Seems, it’s not about the install code logic, but just the Wasm file is invalid?

The wasm was created from a motoko project and I don’t think I’m using gzip.

dfx.json below

{
    "canisters": {
        "treasury": {
            "main": "src/stacked_dao_backend/treasury/main.mo",
            "type": "motoko"
        },
        "governance": {
            "main": "src/stacked_dao_backend/governance/main.mo",
            "type": "motoko"
        },
        "upgrader": {
            "main": "src/stacked_dao_backend/upgrader/main.mo",
            "type": "motoko"
        }
    },
    "networks": {
        "development": {
            "providers": ["https://icp0.io"],
            "type": "persistent"
        },
        "staging": {
            "providers": ["https://icp0.io"],
            "type": "persistent"
        }
    },
    "defaults": {
        "build": {
            "args": "",
            "packtool": "mops sources"
        }
    },
    "output_env_file": ".env",
    "version": 1
}

Maybe you should try specifically using gzip? I think it is the default now(although old stuff shouldn’t break)

From the replica code, it’s just the beginning of the Wasm file should start with either \x00asm or \x1f\x8b\x08.

You could probably just manually check if the Wasm you’re installing starts with one of those signatures. Something like:

find . -name '*.wasm'
xxd <Wasm file> | head -1
jonathangreen@Jonathans-Mac-mini Uploader % xxd ./governance.wasm | head -1
00000000: 0061 736d 0100 0000 01cc 011f 6000 0060  .asm........`..`
jonathangreen@Jonathans-Mac-mini Uploader % gzip ./governance.wasm      
jonathangreen@Jonathans-Mac-mini Uploader % xxd ./governance.wasm.gz | head -1
00000000: 1f8b 0808 a100 5d66 0003 676f 7665 726e  ......]f..govern

Here is the output before and after using gzip

Both still give me the same error when I try to install them programmatically. This is the wasm file generated from both the dfx deploy and dfx build commands and when using the dfx deploy command it installs fine. The upload logic and install logic I am using are from pervious projects that worked, namely TheRegistry, CigDao v1 and the original implementation of CanDB

Does it work locally?

The issue persist locally

Then probably we should make sure the wasm we pass here still starts with those signatures? If it reproduces locally, we can just dump the first few bytes on the console.

There is an error somewhere, we just need to keep looking…

dfx deploy works and I’m using the same wasm generated from that so seems like it has something to so with how dfx is building the wasm

I’d really focus on making sure that the Wasm binary stored in the admin canister is valid. The unsupported canister module format error is really about Wasm binary signature.

How would I do that and why wouldn’t it be invalid when the same wasm deploys successfully when using dfx deploy

As a start, debug.print the size of the wasm before you send it off and make sure it matches what is on disc. If they are the same, slice the first few bytes and last few bytes and make sure they match.

let x = Blob.toArray(wasm);
let xsize = wasm.size();
Debug.print(debug_show(xsize);
Debug.print(debug_show((x[0],x[1],x[2],x[3]));
Debug.print(debug_show((x[xsize-4],x[xsize-3],x[x-2],x[x-1]));

1 Like