# Wrong indication of incompatible layout after upgrade

**URL:** <https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335>\
**Category:** Upgrades\
**Created:** [February 21, 2025, 12:41pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335 "2025-02-21T12:41:16Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![matadorcro](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/matadorcro/32/10677_2.png) [@matadorcro](https://forum.openzeppelin.com/u/matadorcro)\
**Post date:** [February 21, 2025, 12:41pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/1 "2025-02-21T12:41:16Z")

</div>

Hi, I have situation like below, so I have

layout:

uint256  
Data (struct)

I want to add to Data struct at the end, additional variable uint256 data3

Running this with upgrades raises error that layout is not compatible. Is this expected behaviour? As I see it would not affect any layout as information is added at the end of Data struct and Data struct is last variable in storage.

```auto
contracts/test/TestContractV2.sol:19: Upgraded `data` to an incompatible type
  - Bad upgrade from struct TestContract.Data to struct TestContractV2.Data
  - In struct TestContractV2.Data
    - Added `data3`

```

Thank you in advance.

#### 🔢 Code to reproduce

```auto
// INITIAL CONTRACT LAYOUT
contract TestContract is OwnableUpgradeable {
    struct Data {
        uint256 data1;
        uint256 data2;
    }
    /// @custom:storage-location erc7201:openzeppelin.storage.TestContract
    struct TestContractStorage {
        string _version;
        Data data;
    }

    // keccak256(abi.encode(uint256(keccak256("f.storage.TestContract")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant TestContractStorageLocation =
        0xca9ab86016606c0de0fd52d033f885973b1d29b412e722f528ec4c1b4b023800;

    function _getTestContractStorage()
        private
        pure
        returns (TestContractStorage storage $)
    {
        assembly {
            $.slot := TestContractStorageLocation
        }
    }

}

// UPGRADE
contract TestContractV2 is OwnableUpgradeable {
    struct Data {
        uint256 data1;
        uint256 data2;
        uint256 data3;
    }
    /// @custom:storage-location erc7201:openzeppelin.storage.TestContract
    struct TestContractStorage {
        string _version;
        Data data;
    }

    // keccak256(abi.encode(uint256(keccak256("f.storage.TestContract")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant TestContractStorageLocation =
        0xca9ab86016606c0de0fd52d033f885973b1d29b412e722f528ec4c1b4b023800;

    function _getTestContractStorage()
        private
        pure
        returns (TestContractStorage storage $)
    {
        assembly {
            $.slot := TestContractStorageLocation
        }
    }

```

#### 💻 Environment

hardhat-upgrades 3.9.0 . transparent proxy

---

<div class="post-metadata">

**Author:** ![Cainuriel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/cainuriel/32/5410_2.png) [@Cainuriel](https://forum.openzeppelin.com/u/Cainuriel)\
**Post date:** [February 26, 2025, 11:32am UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/2 "2025-02-26T11:32:01Z")

</div>

If I understand you correctly, you want to add one more variable to one of your structures. That's a bad idea.  
I would recommend that you add the variable at the end:

```auto
   struct Data {
        uint256 data1;
        uint256 data2;
    }

    /// @custom:storage-location erc7201:openzeppelin.storage.TestContract
    struct TestContractStorage {
        string _version;
        Data data;
    }

    // New variables should be added here
    uint256 public newVariable;

```

If you are in a development period, deploy new upgradeable contracts if you want to be in struct ones.

Therefore, when creating contracts, it is VERY IMPORTANT to be clear about what data structures you will need. You cannot add properties on demand.

In case the properties may change in the future, convert them into individual mappings, so you can easily add as many as you like.

---

<div class="post-metadata">

**Author:** ![matadorcro](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/matadorcro/32/10677_2.png) [@matadorcro](https://forum.openzeppelin.com/u/matadorcro)\
**Post date:** [February 26, 2025, 11:55am UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/3 "2025-02-26T11:55:26Z")

</div>

Thank you for reply. I understand what you are saying, but this is if I would go with \_gap approach. But I am using erc7201 standard for creating proxy storage layouts and this standard should be compatible with upgrades plugin validation.

---

<div class="post-metadata">

**Author:** ![Cainuriel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/cainuriel/32/5410_2.png) [@Cainuriel](https://forum.openzeppelin.com/u/Cainuriel)\
**Post date:** [February 26, 2025, 1:02pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/4 "2025-02-26T13:02:10Z")

</div>

I don't understand what you mean by ‘with \_gap approach. ‘.  
The ERC721 standard has nothing to do with the requirement to correlate new variables in an updateable contact.

Introducing a variable into an existing structure is not something that is recommended, nor does it say that you can't, although I have no recollection that this can be done.

Perhaps someone else can shed more light about.

---

<div class="post-metadata">

**Author:** ![matadorcro](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/matadorcro/32/10677_2.png) [@matadorcro](https://forum.openzeppelin.com/u/matadorcro)\
**Post date:** [February 26, 2025, 3:32pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/5 "2025-02-26T15:32:07Z")

</div>

I am referring to this:

> **[ERC-7201: Namespaced Storage Layout](https://eips.ethereum.org/EIPS/eip-7201)**
>
> Conventions for the storage location of structs in the namespaced storage pattern.

which is what upgrades plugin supports

> **[Writing Upgradeable Contracts - OpenZeppelin Docs](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#namespaced-storage-layout)**

---

<div class="post-metadata">

**Author:** ![ericglau](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/ericglau/32/15149_2.png) [@ericglau](https://forum.openzeppelin.com/u/ericglau)\
**Post date:** [February 27, 2025, 8:06pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/6 "2025-02-27T20:06:35Z")

</div>

This looks like a valid scenario, and the error seems to be an issue with the validations. Opened an issue here: [https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1136](https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1136)

---

<div class="post-metadata">

**Author:** ![Cainuriel](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/cainuriel/32/5410_2.png) [@Cainuriel](https://forum.openzeppelin.com/u/Cainuriel)\
**Post date:** [February 28, 2025, 3:12pm UTC](https://forum.openzeppelin.com/t/wrong-indication-of-incompatible-layout-after-upgrade/43335/7 "2025-02-28T15:12:28Z")

</div>

I have checked my upgradable smart contracts and yes, I have added at the end of already stored structures a new variable without problems.

But I see what here is asking about is the use of `@custom:storage-location` which, if I understand correctly, one stores the variable outside the memory tree structure.

Now I open question.

Adding variables to the end of the structure has never given me problems but I have not used `@custom:storage-location` in those additions.  
Is this necessary?  
Why has it worked for me?  
@ericglau
