ethereum/go-ethereum · critical
error decoding contract deployer hex %s: %v
Error message
error decoding contract deployer hex %s: %v
What it means
The v2 deployment tree links dependency addresses into the deployer bytecode (replacing __$<id>__$ placeholders) and then hex-decodes the final deployerCode with hex.DecodeString after stripping the 0x prefix. If the resulting string contains non-hex characters or odd length, decoding fails and the code panics with the offending hex and the decode error — this indicates corrupted or badly generated deployment metadata, not a runtime chain condition.
Source
Thrown at accounts/abi/bind/v2/dep_tree.go:117
// Don't re-deploy aliased or previously-deployed contracts
if addr, ok := d.deployedAddrs[metadata.ID]; ok {
return addr, nil
}
// If this contract/library depends on other libraries deploy them
// (and their dependencies) first
deployerCode := metadata.Bin
for _, dep := range metadata.Deps {
addr, err := d.linkAndDeploy(dep)
if err != nil {
return common.Address{}, err
}
// Link their deployed addresses into the bytecode to produce
deployerCode = strings.ReplaceAll(deployerCode, "__$"+dep.ID+"$__", strings.ToLower(addr.String()[2:]))
}
// Finally, deploy the top-level contract.
code, err := hex.DecodeString(deployerCode[2:])
if err != nil {
panic(fmt.Sprintf("error decoding contract deployer hex %s:\n%v", deployerCode[2:], err))
}
addr, tx, err := d.deployFn(d.inputs[metadata.ID], code)
if err != nil {
return common.Address{}, err
}
d.deployedAddrs[metadata.ID] = addr
d.deployerTxs[metadata.ID] = tx
return addr, nil
}
// result returns a DeploymentResult instance referencing contracts deployed
// and not including any overrides specified for this deployment.
func (d *depTreeDeployer) result() *DeploymentResult {
// filter the override addresses from the deployed address set.
for pattern := range d.deployedAddrs {
if _, ok := d.deployerTxs[pattern]; !ok {
delete(d.deployedAddrs, pattern)
}View on GitHub (pinned to 6bb0588ad8)
Solutions
- Regenerate the deployment metadata/binaries from a clean build (solc + abigen/bind tooling) instead of patching hex by hand.
- Verify every __$id$__ placeholder in metadata.Bin has a matching dependency in metadata.Deps so substitution leaves pure hex.
- Sanity-check the string before deploy: even length and only [0-9a-fA-F] after stripping 0x.
- Inspect the panic text: it prints the exact bad hex, showing where corruption begins.
Example fix
// before meta.Bin = strings.Replace(meta.Bin, "__$lib__$__", "0x9a0f...", 1) // embeds 0x -> invalid hex // after meta.Bin = strings.Replace(meta.Bin, "__$lib__$__", "9a0f...", 1) // bare hex, no 0x
Defensive patterns
Strategy: validation
Validate before calling
func validHexCode(code string) bool {
c := strings.TrimPrefix(code, "0x")
if len(c)%2 != 0 {
return false
}
for _, r := range c {
if !strings.ContainsRune("0123456789abcdefABCDEF", r) {
return false
}
}
return true
}
// guard: if !validHexCode(strings.ReplaceAll(meta.Bin, placeholder, bareHexAddr)) { return errors.New("corrupt deployer bin") } Type guard
func isLinkedBytecode(bin string) bool {
return !strings.Contains(bin, "__$") && validHexCode(bin)
} Try / catch
defer func() {
if r := recover(); r != nil {
if msg, _ := r.(string); strings.HasPrefix(msg, "error decoding contract deployer hex") {
return common.Address{}, errors.New("deployer bytecode is not valid hex; regenerate bind metadata")
}
panic(r)
}
}() Prevention
- Never hand-edit linked bytecode; regenerate with abigen/solc.
- Ensure every link placeholder has a dependency entry.
- Checksum/validate bin artifacts in CI before deployment runs.
When it happens
Trigger: deployFn path where metadata.Bin contains invalid hex after dependency substitution: an unresolved/misspelled placeholder, a bin artifact that was truncated or contains 'undefined' from a JS build step, or manual editing of the linked bytecode string.
Common situations: Feeding bind v2 DeploymentMetadata assembled by hand or by a buggy codegen step; solc output post-processing that mangles the bin (link placeholders replaced with address strings including '0x' or empty values); partial file writes leaving truncated hex.
Related errors
- nil chainID
- Could not create random uuid: %v
- key generation: could not read from random source:
- key generation: ecdsa.GenerateKey failed:
- reading from crypto/rand failed:
AI-assisted analysis of ethereum/go-ethereum@6bb0588ad8 (2026-08-15).
Data as JSON: /api/errors/252d66fda7666593.
Report an issue: GitHub.