unionlabs/union · error
newOperatorAddress is not of type string
Error message
newOperatorAddress is not of type string
What it means
getCommandArgs asserts that appOpts.Get(server.KeyNewOpAddr) yields a Go string (the new validator operator's bech32 address). If the option is absent (nil) or stored as another type, the assertion fails and the process panics during testnet setup.
Solutions
- Invoke through `uniond testnet` so the operator-address flag is registered and defaults bind
- Programmatically: viper.Set(server.KeyNewOpAddr, "union1...") with an actual string value
- Verify the option source — viper keys are lowercase; a casing mismatch yields nil
- In a fork, convert these panics into returned errors for embeddability
Defensive patterns
Strategy: type-guard
Validate before calling
vpr.Set(server.KeyNewOpAddr, "union1operator...") // must be a Go string, present even if only a default
Type guard
func optString(appOpts servertypes.AppOptions, key string) (string, bool) {
v, ok := appOpts.Get(key).(string)
return v, ok
} Prevention
- Bind testnet flags via the standard command so defaults exist
- Use lowercase viper keys — casing mismatches yield nil and trip the assertion
- Avoid sourcing these options from JSON where types degrade to floats/objects
- In forks, prefer returning an error naming the missing key
When it happens
Trigger: Building the testnet app in-process without setting server.KeyNewOpAddr; a wrapper command that does not bind the flag into viper; the option loaded from a structured config file into a non-string JSON type.
Common situations: Test harnesses and custom tooling invoking the app builder; refactors of the testnet command flags; configs where the value deserializes as a number or nested object.
Related errors
- newValAddr is not of type bytes.HexBytes
- newValPubKey is not of type crypto.PubKey
- upgradeToTrigger is not of type string
- error while creating a new delegation period record
- error while incrementing period
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/ac72e22dea0a716c.
Report an issue: GitHub.
Appendix: source
Thrown at uniond/cmd/uniond/cmd/testnet.go:231
}
// 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
// validate and set accounts to fund
accountsString := cast.ToString(appOpts.Get(flagAccountsToFund))
for _, account := range strings.Split(accountsString, ",") {
if account != "" {
addr, err := sdk.AccAddressFromBech32(account)
if err != nil {
return args, fmt.Errorf("invalid bech32 address format %w", err)
}
args.accountsToFund = append(args.accountsToFund, addr)View on GitHub (pinned to 031785bb6d)