{"record":{"id":"ac72e22dea0a716c","repo":"unionlabs/union","slug":"newoperatoraddress-is-not-of-type-string","errorCode":null,"errorMessage":"newOperatorAddress is not of type string","messagePattern":"newOperatorAddress is not of type string","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"uniond/cmd/uniond/cmd/testnet.go","lineNumber":231,"sourceCode":"}\n\n// parse the input flags and returns valArgs\nfunc getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) {\n\targs := valArgs{}\n\n\tnewValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes)\n\tif !ok {\n\t\tpanic(\"newValAddr is not of type bytes.HexBytes\")\n\t}\n\targs.newValAddr = newValAddr\n\tnewValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey)\n\tif !ok {\n\t\tpanic(\"newValPubKey is not of type crypto.PubKey\")\n\t}\n\targs.newValPubKey = newValPubKey\n\tnewOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string)\n\tif !ok {\n\t\tpanic(\"newOperatorAddress is not of type string\")\n\t}\n\targs.newOperatorAddress = newOperatorAddress\n\tupgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string)\n\tif !ok {\n\t\tpanic(\"upgradeToTrigger is not of type string\")\n\t}\n\targs.upgradeToTrigger = upgradeToTrigger\n\n\t// validate  and set accounts to fund\n\taccountsString := cast.ToString(appOpts.Get(flagAccountsToFund))\n\n\tfor _, account := range strings.Split(accountsString, \",\") {\n\t\tif account != \"\" {\n\t\t\taddr, err := sdk.AccAddressFromBech32(account)\n\t\t\tif err != nil {\n\t\t\t\treturn args, fmt.Errorf(\"invalid bech32 address format %w\", err)\n\t\t\t}\n\t\t\targs.accountsToFund = append(args.accountsToFund, addr)","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/uniond/cmd/uniond/cmd/testnet.go#L213-L249","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"vpr.Set(server.KeyNewOpAddr, \"union1operator...\") // must be a Go string, present even if only a default","typeGuard":"func optString(appOpts servertypes.AppOptions, key string) (string, bool) {\n\tv, ok := appOpts.Get(key).(string)\n\treturn v, ok\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["cosmos-sdk","testnet","flags","panic","golang"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}