Contract upgrade failed because variables are deleted in openzepplin 5.0

I have an ERC721Upgradeable contract deployed to Ethereum main net, using the openzepplin 4.x. Recently I wanted to upgrade our implementation using the Openzepplin 5.0 library. However, after I modify the code, adopted the 5.0 features and ran upgradeProxy in hardhat, i got the following error:

```Initializable: Deleted _initialized

Keep the variable even if unused

Initializable: Deleted _initializing

Keep the variable even if unused

ContextUpgradeable: Deleted __gap

Keep the variable even if unused

ERC165Upgradeable: Deleted __gap

Keep the variable even if unused

ERC721Upgradeable: Deleted _name

Keep the variable even if unused

ERC721Upgradeable: Deleted _symbol

Keep the variable even if unused

ERC721Upgradeable: Deleted _owners

Keep the variable even if unused

ERC721Upgradeable: Deleted _balances

Keep the variable even if unused

ERC721Upgradeable: Deleted _tokenApprovals

Keep the variable even if unused

ERC721Upgradeable: Deleted _operatorApprovals

Keep the variable even if unused

ERC721Upgradeable: Deleted __gap

Keep the variable even if unused

ERC721EnumerableUpgradeable: Deleted _ownedTokens

Keep the variable even if unused

ERC721EnumerableUpgradeable: Deleted _ownedTokensIndex

Keep the variable even if unused

ERC721EnumerableUpgradeable: Deleted _allTokens

Keep the variable even if unused

ERC721EnumerableUpgradeable: Deleted _allTokensIndex

Keep the variable even if unused

ERC721EnumerableUpgradeable: Deleted __gap

Keep the variable even if unused

ERC721BurnableUpgradeable: Deleted __gap

Keep the variable even if unused

AccessControlUpgradeable: Deleted _roles

Keep the variable even if unused

AccessControlUpgradeable: Deleted __gap

Keep the variable even if unused

ReentrancyGuardUpgradeable: Deleted _status

Keep the variable even if unused

ReentrancyGuardUpgradeable: Deleted __gap

Keep the variable even if unused


These built in variables are either removed in Openzepplin 5.0 or moved to inner structures so I cannot upgrade the implementation contract without messing up storage. How should I resolve this?

#### 💻 Environment
Hardhat on Mac

It is NOT safe to upgrade existing deployments from 4.x to 5.0 because they use different storage layouts.

The OpenZeppelin Contracts 5.0 readme states:

Important
OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at Backwards Compatibility.

1 Like

very helpful, thank you.

1 Like

Quite old issue, but has anyone tried to just add the gap[xx] to the implementation contracts to keep using the storage slots at the right location and then just use the new proxy contracts with their individual storage slots which are anywhere somewhere (pseudo) randomly located? I am inclined to try, since a lot of functionality is only available in oz 5 contracts (e.g. EIP712 utils), and porting them around is a mess.

@tomw1808 That would not work by default, since OpenZeppelin Contracts v5 would read from the namespaced storage structs rather than the old storage slots. Therefore the old variables would not be used.