openzeppelin-upgrades icon indicating copy to clipboard operation
openzeppelin-upgrades copied to clipboard

Error: `Define an initializer function and use it to call the initializers of parent contracts`

Open vladimir-trifonov opened this issue 11 months ago • 6 comments

I get

      test/contracts/xxxV2.sol:20: Missing initializer
          Define an initializer function and use it to call the initializers of parent contracts
          https://zpl.in/upgrades/error-001

when I try to upgrade from v1 to v2 of the smart contract. This error happens when

npx @openzeppelin/upgrades-core@^1.42.0 validate out/build-info --contract test/contracts/xxxV2.sol:xxxV2 --requireReference

is executed. I didn't have this error with @openzeppelin/upgrades-core v1.41.0.

My v2 initializer:

function initializeV2() public reinitializer(2) {}

vladimir-trifonov avatar Feb 11 '25 08:02 vladimir-trifonov

hey @vladimir-trifonov I am getting a similar issue #1124, do you remember which version of the @openzeppelin/hardhat-upgrades package did @openzeppelin/upgrades-core v1.41.0 pointed too ?

viraj124 avatar Feb 11 '25 10:02 viraj124

hey @vladimir-trifonov I am getting a similar issue #1124, do you remember which version of the @openzeppelin/hardhat-upgrades package did @openzeppelin/upgrades-core v1.41.0 pointed too ?

I was having the same issue as you before, but I removed the

function initialize

in the upgraded contract, because either way, I don't need it.

But this current issue is breaking the upgrade altogether. But you're right, there is some issue with those initializers going on.

vladimir-trifonov avatar Feb 11 '25 11:02 vladimir-trifonov

hmm I had initialize defined before and it was working fine but for some reason now it doesn't since last week or so which is super weird

viraj124 avatar Feb 11 '25 11:02 viraj124

We added checks to detect issues in parent initializer calls in @openzeppelin/[email protected]. In your scenario, since you are upgrading and if you don't need an initializer in your upgraded contract, you can skip the missing-initializer check.

From Foundry:

Options memory opts;
opts.unsafeAllow = "missing-initializer";
Upgrades.upgradeProxy(proxy, "MyContractV2.sol", data, opts);

From Hardhat:

await upgrades.upgradeProxy(proxyAddress, MyContractV2, {
  unsafeAllow: ['missing-initializer'],
});

We may consider fixing the plugin to skip this by default when upgrading.

ericglau avatar Feb 11 '25 16:02 ericglau

I saw this missing-initializer check, but I didn't want to use it since I have initializer in my upgraded contract e.g.:

function initializeV2() public reinitializer(2) {
 ...
}

vladimir-trifonov avatar Feb 12 '25 08:02 vladimir-trifonov

The plugin currently doesn't validate reinitializers, but we may add https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1122 to allow you to specify that your initializeV2 function is the initializer that should be validated.

ericglau avatar Feb 12 '25 16:02 ericglau

This is addressed in @openzeppelin/[email protected] which allows you to annotate your reinitializer function with NatSpec @custom:oz-upgrades-validate-as-initializer, which will cause it to be validated as an initializer.

See details in https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#validating_initializers

To be clear:

  • If your new implementation is not meant to be used for new proxy deployments, but you only intend to upgrade from previous versions, you can use unsafeAllow with missing-initializer as described in my comment above.
  • If your new implementation's reinitializer is also meant to be used for new proxy deployments, you can annotate it with @custom:oz-upgrades-validate-as-initializer so that it is included in validations.

ericglau avatar Apr 11 '25 20:04 ericglau