Updating controllers (dfx 0.14.0)

An attempt to update the canister controllers fails.
I use the standard canister settings update code in motoko.

Part of the code

    let new_settings: CanisterSettings = {
        controllers = ?List.toArray(list);
        compute_allocation = settings.compute_allocation;
        memory_allocation = settings.memory_allocation;
        freezing_threshold = settings.freezing_threshold;
    await ic_actor.update_settings({
            canister_id = Principal.fromActor(self);
            settings = new_settings;

In list add new controller. And the ones that are available are saved.

Standard error:

Error: Failed update call.
Caused by: Failed update call.
The Replica returned an error: code 4, message: “Only the controllers of the canister xifbj-tqaaa-aaaaa-aaauq-cai can control it.
Canister’s controllers: rwlgt-iiaaa-aaaaa-aaaaa-cai mlx7d-nlzwm-jsiyr-txxc2-mlgsf-hafo6-73wnd-du4xx-f2tsd-mjtum-pae
Sender’s ID: xifbj-tqaaa-aaaaa-aaauq-cai”

I can still add another controller via the standart command dfx. This team works great:
dfx canister update-settings authorization-rbac --add-controller

All actions are performed from the command line under the controller of the owner of the canister.

Another question is, where did this canister in the controllers come from rwlgt-iiaaa-aaaaa-aaaaa-cai?
Since they are updated on the canister (it is the only one) xifbj-tqaaa-aaaaa-aaauq-cai

What’s going wrong? Maybe this is not possible with the current version of dfx?

I will supplement the information for informativeness. The canister controllers are:

opt vec {
principal “rwlgt-iiaaa-aaaaa-aaaaa-cai”;
principal “mlx7d-nlzwm-jsiyr-txxc2-mlgsf-hafo6-73wnd-du4xx-f2tsd-mjtum-pae”;

Calls to the canister are made from under mlx7d-nlzwm-jsiyr-txxc2-mlgsf-hafo6-73wnd-du4xx-f2tsd-mjtum-pae

I also do checks:

public shared({caller}) func whoami_caller() : async Text{*
   return Principal.toText(caller);*

Result: (“mlx7d-nlzwm-jsiyr-txxc2-mlgsf-hafo6-73wnd-du4xx-f2tsd-mjtum-pae”)

 public shared({caller}) func canister_id() : async Principal{*
   return Principal.fromActor(self);*

Result: (principal “xifbj-tqaaa-aaaaa-aaauq-cai”)

Thanks for the detailed writeup. I wish all bug reports had so much info…

What you are trying to do:

  • make a dfx call from identity mlx7d-nlzwm-jsiyr-txxc2-mlgsf-hafo6-73wnd-du4xx-f2tsd-mjtum-pae to canister xifbj-tqaaa-aaaaa-aaauq-cai
  • canister xifbj-tqaaa-aaaaa-aaauq-cai makes a call to the management canister to update the settings of canister xifbj-tqaaa-aaaaa-aaauq-cai
  • the management canister checks if the sender of the update-settings message (canister xifbj-tqaaa-aaaaa-aaauq-cai) is in the list of controllers
  • it is not, therefore the update will not be executed

It will work if you add the canister’s own principal to its controllers.

This is most likely your cycles wallet, which is needed to create your canister in the first place. dfx by default adds your dfx identity and the wallet’s identity to the list of controllers

1 Like

Yes it works.
Provided that you need to use dfx.

dfx canister update-settings this_canister_id --add-controller this_canister_id

And only then add any Principal from the code…

1 Like

You don’t have to use dfx if you don’t create your canister via dfx’s default settings

And how can this be implemented?

Is it about here?

 "declarations": {
          "title": "Declarations Configuration",
          "description": "Defines which canister interface declarations to generate, and where to generate them.",
          "default": {
            "bindings": null,
            "env_override": null,
            "node_compatibility": false,
            "output": null
          "allOf": [
              "$ref": "#/definitions/CanisterDeclarationsConfig"

No, it’s when you create the canister.

If you go through the management canister (interface) to create the canister, you can specify a list of controllers.

When you go through dfx, there’s the --controller option on dfx canister create that you can use

But I don’t create canisters from the code in motoko. In fact, I have one canister. It is created once during deployment.

In this case, if you’re deploying with dfx you indeed have to do it manually or as part of your deployment script

  • Maybe in the future, add a property to the dfx circuit in which the canister adds itself to the controllers?
  • Or add the ability to register controllers in the dfx json schema. (But then we don’t know the generated ID yet)

Ok, Thanks