datahaven-xyz/datahaven · critical · Error

InvalidUpgradeParameters

InvalidUpgradeParameters

Error message

InvalidUpgradeParameters

What it means

The system-v2 pallet's `upgrade` extrinsic throws `Error::InvalidUpgradeParameters` when the supplied `impl_address` or `impl_code_hash` is zero. Upgrading the system contract to a zero address or zero code hash would brick the EVM-side system contract, so these degenerate values are rejected up front (after governance-origin verification).

Solutions

  1. Deploy the new implementation contract first and use its real address and code hash in the upgrade call.
  2. Validate `impl_address != H160::zero()` and `impl_code_hash != H256::zero()` in the proposal/submitting script before dispatching.
  3. Verify argument ordering when constructing the extrinsic call data.

Example fix

// before
let addr = H160::zero();
SystemV2::upgrade(origin, addr, H256::zero(), initializer)?; // InvalidUpgradeParameters

// after
let addr = deployed_impl_address; // from successful forge/Foundry deploy output
let code_hash = keccak256(deployed_impl_code);
assert!(!addr.is_zero() && !code_hash.is_zero());
SystemV2::upgrade(origin, addr, code_hash, initializer)?;
Defensive patterns

Strategy: validation

Validate before calling

if (implAddress === '0x0000000000000000000000000000000000000000' || implCodeHash === '0x' + '00'.repeat(32)) throw new Error('zero upgrade target');

Type guard

function isNonZeroUpgradeTarget(addr, hash) { return addr != null && !/^0x0+$/.test(addr) && hash != null && !/^0x(00)*$/.test(hash); }

Try / catch

try { await api.tx.systemV2.upgrade(implAddress, implCodeHash, initializer).signAndSend(council); } catch (e) { if (String(e).includes('InvalidUpgradeParameters')) abortProposal(); else throw e; }

Prevention

When it happens

Trigger: Calling `upgrade(origin, impl_address, impl_code_hash, initializer)` via the governance origin where `impl_address == H160::zero()` or `impl_code_hash == H256::zero()` — typically uninitialized parameters or a failed contract deployment whose outputs defaulted to zero.

Common situations: Proposal/automation scripts passing default H160/H256 values because the new implementation failed to deploy; copying upgrade calldata with placeholder zeros; indexer or multisig tooling mixing up argument order so zeros land in these fields.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13). Data as JSON: /api/errors/7c350a521a0cd230. Report an issue: GitHub.

Appendix: source

Thrown at operator/pallets/system-v2/src/lib.rs:146

        ///
        /// Fee required: No
        ///
        /// - `origin`: Must be `Root`.
        /// - `impl_address`: The address of the implementation contract.
        /// - `impl_code_hash`: The codehash of the implementation contract.
        /// - `initializer`: Optionally call an initializer on the implementation contract.
        #[pallet::call_index(3)]
        #[pallet::weight((<T as pallet::Config>::WeightInfo::upgrade(), DispatchClass::Operational))]
        pub fn upgrade(
            origin: OriginFor<T>,
            impl_address: H160,
            impl_code_hash: H256,
            initializer: Initializer,
        ) -> DispatchResult {
            let origin_location = T::GovernanceOrigin::ensure_origin(origin)?;
            let origin = Self::location_to_message_origin(origin_location)?;

            ensure!(
                !impl_address.eq(&H160::zero()) && !impl_code_hash.eq(&H256::zero()),
                Error::<T>::InvalidUpgradeParameters
            );

            let initializer_params_hash: H256 = blake2_256(initializer.params.as_ref()).into();

            let command = Command::Upgrade {
                impl_address,
                impl_code_hash,
                initializer,
            };
            Self::send(origin, command, 0)?;

            Self::deposit_event(Event::<T>::Upgrade {
                impl_address,
                impl_code_hash,
                initializer_params_hash,
            });

View on GitHub (pinned to edcb13dbbc)