# Potential false positive "Missing initializer calls for one or more parent contracts"

**URL:** <https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911>\
**Category:** Upgrades\
**Tags:** erc20, upgrades\
**Created:** [April 23, 2025, 6:01pm UTC](https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911 "2025-04-23T18:01:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Heuristik](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/heuristik/32/17147_2.png) [@Heuristik](https://forum.openzeppelin.com/u/Heuristik)\
**Post date:** [April 23, 2025, 6:01pm UTC](https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911/1 "2025-04-23T18:01:48Z")

</div>

#### 🔢 Code to reproduce

I think I've handled the initializer calls for my upgradeable ERC20 token contract correctly.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol";

import {Test} from "forge-std/Test.sol";

contract Token is ERC20Upgradeable, UUPSUpgradeable {
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address initialOwner) external initializer {
        __Token_init(initialOwner);
    }

    function __Token_init(address initialOwner) internal onlyInitializing {
        __Context_init_unchained();
        __ERC20_init_unchained("Token", "TOK");
        __UUPSUpgradeable_init_unchained();

        __Token_init_unchained(initialOwner);
    }

    function __Token_init_unchained(address initialOwner) internal onlyInitializing {
        _mint(initialOwner, 100);
    }

    function _authorizeUpgrade(address newImplementation) internal pure override {
        {
            newImplementation;
        }
        // NOTE: In this MWE, anyone can upgrade. DO NOT USE IN PRODUCTION.
    }
}

```

However, deploying it with `Upgrades.deployUUPSProxy` in the test below

```solidity
contract TokenTest is Test {
    address internal _defaultSender;
    Token internal _tokenProxy;

    function setUp() public {
        (, _defaultSender,) = vm.readCallers();

        // Deploy proxy and mint tokens for the `_defaultSender`.
        vm.prank(_defaultSender);
        _tokenProxy = Token(
            Upgrades.deployUUPSProxy({
                contractName: "Token.sol:Token",
                initializerData: abi.encodeCall(Token.initialize, _defaultSender)
            })
        );
    }

    function test_balance() public view {
        assertEq(_tokenProxy.balanceOf(_defaultSender), 100);
    }
}

```

fails with the following error

```bash
[FAIL: revert: Upgrade safety validation failed:
✘ src/Token.sol:Token

    src/Token.sol:29: Missing initializer calls for one or more parent contracts: `ERC20Upgradeable`
        Call the parent initializers in your initializer function
        https://zpl.in/upgrades/error-001

FAILED] setUp() (gas: 0)

```

I've provided a minimal example to reproduce the error in this repo [https://github.com/heueristik/token](https://github.com/heueristik/token).  
To reproduce the problem, run

```bash
git clone --recursive https://github.com/heueristik/token
cd token
forge clean && forge build && forge test

```

Here is the workflow in which the test from above fails: [https://github.com/heueristik/token/actions/runs/14624117496/job/41031361022#step:7:10](https://github.com/heueristik/token/actions/runs/14624117496/job/41031361022#step:7:10)

#### 💻 Environment

- OS:
  - macOS 15.3.1 (sequoia)
  - Apple M1

- Forge

```auto
forge Version: 1.0.0-stable
Commit SHA: e144b82070619b6e10485c38734b4d4d45aebe04
Build Timestamp: 2025-02-13T20:02:34.979686000Z (1739476954)
Build Profile: maxperf

```

- OZ
  - openzeppelin-contracts-upgradeable: `v5.3.0`
  - openzeppelin-foundry-upgrades: `v0.4.0`

Am I doing something wrong? Thank you for your help

---

<div class="post-metadata">

**Author:** ![Heuristik](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/heuristik/32/17147_2.png) [@Heuristik](https://forum.openzeppelin.com/u/Heuristik)\
**Post date:** [April 23, 2025, 6:44pm UTC](https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911/2 "2025-04-23T18:44:40Z")

</div>

It seems like the `Upgrades` library thinks that `__Token_init_unchained` is an initializer that must call the parent initializer as well.

---

<div class="post-metadata">

**Author:** ![Heuristik](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/heuristik/32/17147_2.png) [@Heuristik](https://forum.openzeppelin.com/u/Heuristik)\
**Post date:** [April 24, 2025, 7:03am UTC](https://forum.openzeppelin.com/t/potential-false-positive-missing-initializer-calls-for-one-or-more-parent-contracts/43911/3 "2025-04-24T07:03:33Z")

</div>

This got answered here [https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1150](https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/1150)

> Thanks for reporting. It seems like the fix should be to avoid checking for parent initializer calls if the initializer name ends with `_unchained`, since that is its typical usage pattern.  
> As a workaround for now, you can add `/// @custom:oz-upgrades-unsafe-allow missing-initializer-call` above the `__Token_init_unchained` function.
