EVM / Solidity Error 0x118cdaa7: OwnableUnauthorizedAccount
An onlyOwner function was called by an address that is not owner(). The data contains the caller; send from the owner account, or transfer ownership — and remember v5 requires an initialOwner in the constructor.
Identify: does your log match?
ContractFunctionExecutionError: The contract function "setFee" reverted.
Error: OwnableUnauthorizedAccount(address account)
(0x70997970C51812dc3A010C7d01b50e0d17dc79C8)
Raw revert data:
0x118cdaa700000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8
Version: viem@2.21.37- High
Calling from the wrong account
The script or wallet uses a different signer than the deployer that owns the contract.
- Medium
Owner set to the factory or deployer contract
With OZ v5 Ownable(initialOwner), passing msg.sender inside a factory makes the factory the owner, not the EOA.
- Medium
Ownership already transferred or renounced
transferOwnership to a multisig or renounceOwnership() means the old key can no longer call admin functions.
Fix
Pass the intended owner explicitly (OZ v5)
contract Vault is Ownable { constructor() Ownable(msg.sender) {} } // deployed via a factory: owner == factory address
contract Vault is Ownable2Step { constructor(address initialOwner) Ownable(initialOwner) {} } // factory: new Vault(msg.sender);
An explicit initialOwner makes ownership deterministic across factories and scripts. Ownable2Step requires the new owner to accept, avoiding typos.
Verify: reproduce it on purpose
$ cast decode-error 0x118cdaa700000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8 --sig "OwnableUnauthorizedAccount(address)"Run it against a dev environment to trigger 0x118cdaa7 on purpose and test your error handler.
Prevent
- Use a multisig as owner in production.
- Prefer Ownable2Step for transfers.
- Log owner() in deploy scripts after deployment.
FAQ
How do I see who the owner is?
cast call <contract> "owner()(address)" --rpc-url $RPC_URL returns the current owner.
Why does OZ v5 Ownable require a constructor argument?
v5 removed the implicit msg.sender owner to prevent factory and proxy ownership mistakes. Pass initialOwner explicitly.
What about AccessControl roles?
AccessControl reverts with AccessControlUnauthorizedAccount(account, role), selector 0xe2517d3f. Grant the role with grantRole.
Related errors
Last verified 2026-10-18 · Source: 4byte/OpenChain signatures + OpenZeppelin v5 custom errors + Panic codes · Official docs ↗ · ~2,400 searches/mo