unionlabs/union · error

newValAddr is not of type bytes.HexBytes

Error message

newValAddr is not of type bytes.HexBytes

What it means

getCommandArgs builds testnet arguments from the app options map with Go type assertions. server.KeyNewValAddr must already hold a bytes.HexBytes value; a nil entry (flag never set) or a value of another type fails the assertion and panics. These typed values are normally injected by the testnet command's flag wiring into viper-backed appOpts.

Source

Thrown at uniond/cmd/uniond/cmd/testnet.go:221

		if err != nil {
			panic(err)
		}
		err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins)
		if err != nil {
			panic(err)
		}
	}

	return app
}

// parse the input flags and returns valArgs
func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) {
	args := valArgs{}

	newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes)
	if !ok {
		panic("newValAddr is not of type bytes.HexBytes")
	}
	args.newValAddr = newValAddr
	newValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey)
	if !ok {
		panic("newValPubKey is not of type crypto.PubKey")
	}
	args.newValPubKey = newValPubKey
	newOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string)
	if !ok {
		panic("newOperatorAddress is not of type string")
	}
	args.newOperatorAddress = newOperatorAddress
	upgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string)
	if !ok {
		panic("upgradeToTrigger is not of type string")
	}
	args.upgradeToTrigger = upgradeToTrigger

View on GitHub (pinned to 031785bb6d)

Solutions

  1. Run via the real `uniond testnet` CLI so the server flags are registered and bound into appOpts
  2. When driving programmatically, populate the options first: viper.Set(server.KeyNewValAddr, bytes.HexBytes(...)) plus the other server.Key* values
  3. Do not set the value from a config file as a string — the assertion requires the concrete bytes.HexBytes type
  4. If you need an embeddable API, replace the panics in a fork with an error return listing the missing key

Example fix

// before
newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes)
if !ok {
  panic("newValAddr is not of type bytes.HexBytes")
}

// after — populate appOpts with typed values before building the testnet app
vpr := viper.New()
vpr.Set(server.KeyNewValAddr, bytes.HexBytes(valAddrBytes))
vpr.Set(server.KeyUserPubKey, ed25519.PubKey{Key: pubKeyBytes}) // crypto.PubKey value, not a string
vpr.Set(server.KeyNewOpAddr, operatorBech32)
vpr.Set(server.KeyTriggerTestnetUpgrade, "")
vpr.Set("accounts-to-fund", "")
appOpts := servertypes.AppOptions(vpr)
Defensive patterns

Strategy: type-guard

Validate before calling

// When driving the testnet app outside the CLI, seed viper with typed values
vpr := viper.New()
vpr.Set(server.KeyNewValAddr, bytes.HexBytes(valAddrBytes))
vpr.Set(server.KeyUserPubKey, ed25519.PubKey{Key: pubKeyBytes})
vpr.Set(server.KeyNewOpAddr, "union1operator...")
vpr.Set(server.KeyTriggerTestnetUpgrade, "")
vpr.Set("accounts-to-fund", "")
appOpts := servertypes.AppOptions(vpr)

Type guard

func optHexBytes(appOpts servertypes.AppOptions, key string) (bytes.HexBytes, bool) {
	v, ok := appOpts.Get(key).(bytes.HexBytes) // ok is false for nil (missing flag) too
	return v, ok
}

Prevention

When it happens

Trigger: Invoking the testnet app-construction path programmatically (tests, embedding, custom commands) without setting server.KeyNewValAddr in appOpts; a modified testnet command that stops binding its flags into viper.

Common situations: In-process tests that build the app the way `uniond testnet` does; wrapping the testnet command in another binary; refactor dropping flag registration so appOpts.Get returns nil.

Related errors


AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16). Data as JSON: /api/errors/bd69c3bbbfe94f8d. Report an issue: GitHub.