unionlabs/union · error
upgradeToTrigger is not of type string
Error message
upgradeToTrigger is not of type string
What it means
The last of getCommandArgs' assertions: server.KeyTriggerTestnetUpgrade must be present as a string (the upgrade name the local testnet should trigger, empty when unused). Missing option or wrong type panics. Note the next option, accounts-to-fund, is read with cast.ToString instead — showing the tolerant pattern these four panics do not use.
Source
Thrown at uniond/cmd/uniond/cmd/testnet.go:236
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)
}
}
// home dir
homeDir := cast.ToString(appOpts.Get(flags.FlagHome))View on GitHub (pinned to 031785bb6d)
Solutions
- Run the standard `uniond testnet` command so all server.Key* flags are bound
- When constructing appOpts yourself, set an explicit value even if empty: viper.Set(server.KeyTriggerTestnetUpgrade, "")
- Check for typos/casing in option keys — appOpts.Get on a missing key returns nil and trips the assertion
- Fork-friendly change: read with cast.ToString and validate, mirroring the accounts-to-fund line below it
Defensive patterns
Strategy: type-guard
Validate before calling
vpr.Set(server.KeyTriggerTestnetUpgrade, "") // empty string is valid; absence (nil) panics
Type guard
func optTrigger(appOpts servertypes.AppOptions) (string, bool) {
v, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string)
return v, ok
} Prevention
- Set explicit defaults for every server.Key* option when constructing appOpts yourself
- Keep custom testnet wrappers registering the full flag set
- Mirror the tolerant cast.ToString pattern used for accounts-to-fund when forking
- Cover programmatic testnet construction with a smoke test
When it happens
Trigger: Programmatic testnet app construction without setting KeyTriggerTestnetUpgrade; a custom command dropping the flag binding; the value supplied as a non-string type in appOpts.
Common situations: Tests embedding the testnet runner; wrappers around the testnet command; option maps built from JSON where the field is absent or typed differently.
Related errors
- newValAddr is not of type bytes.HexBytes
- newValPubKey is not of type crypto.PubKey
- newOperatorAddress is not of type string
- error while incrementing period: %w
- error while creating a new delegation period record: %w
AI-assisted analysis of unionlabs/union@031785bb6d (2026-08-16).
Data as JSON: /api/errors/64070f54a0703911.
Report an issue: GitHub.