{"record":{"id":"bd69c3bbbfe94f8d","repo":"unionlabs/union","slug":"newvaladdr-is-not-of-type-bytes-hexbytes","errorCode":null,"errorMessage":"newValAddr is not of type bytes.HexBytes","messagePattern":"newValAddr is not of type bytes\\.HexBytes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"uniond/cmd/uniond/cmd/testnet.go","lineNumber":221,"sourceCode":"\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\terr = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\n\treturn app\n}\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","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/uniond/cmd/uniond/cmd/testnet.go#L203-L239","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run via the real `uniond testnet` CLI so the server flags are registered and bound into appOpts","When driving programmatically, populate the options first: viper.Set(server.KeyNewValAddr, bytes.HexBytes(...)) plus the other server.Key* values","Do not set the value from a config file as a string — the assertion requires the concrete bytes.HexBytes type","If you need an embeddable API, replace the panics in a fork with an error return listing the missing key"],"exampleFix":"// before\nnewValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes)\nif !ok {\n  panic(\"newValAddr is not of type bytes.HexBytes\")\n}\n\n// after — populate appOpts with typed values before building the testnet app\nvpr := viper.New()\nvpr.Set(server.KeyNewValAddr, bytes.HexBytes(valAddrBytes))\nvpr.Set(server.KeyUserPubKey, ed25519.PubKey{Key: pubKeyBytes}) // crypto.PubKey value, not a string\nvpr.Set(server.KeyNewOpAddr, operatorBech32)\nvpr.Set(server.KeyTriggerTestnetUpgrade, \"\")\nvpr.Set(\"accounts-to-fund\", \"\")\nappOpts := servertypes.AppOptions(vpr)","handlingStrategy":"type-guard","validationCode":"// When driving the testnet app outside the CLI, seed viper with typed values\nvpr := viper.New()\nvpr.Set(server.KeyNewValAddr, bytes.HexBytes(valAddrBytes))\nvpr.Set(server.KeyUserPubKey, ed25519.PubKey{Key: pubKeyBytes})\nvpr.Set(server.KeyNewOpAddr, \"union1operator...\")\nvpr.Set(server.KeyTriggerTestnetUpgrade, \"\")\nvpr.Set(\"accounts-to-fund\", \"\")\nappOpts := servertypes.AppOptions(vpr)","typeGuard":"func optHexBytes(appOpts servertypes.AppOptions, key string) (bytes.HexBytes, bool) {\n\tv, ok := appOpts.Get(key).(bytes.HexBytes) // ok is false for nil (missing flag) too\n\treturn v, ok\n}","tryCatchPattern":null,"preventionTips":["Prefer the uniond testnet CLI, which binds all server.Key* flags into appOpts","When embedding, set every option with the exact Go type the assertion expects","Remember a missing key returns nil, which fails the type assertion just like a wrong type","Add a regression test that constructs the testnet app with a fully populated appOpts"],"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"}