{"record":{"id":"139203ef5ac5dcc9","repo":"unionlabs/union","slug":"newvalpubkey-is-not-of-type-crypto-pubkey","errorCode":null,"errorMessage":"newValPubKey is not of type crypto.PubKey","messagePattern":"newValPubKey is not of type crypto\\.PubKey","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"uniond/cmd/uniond/cmd/testnet.go","lineNumber":226,"sourceCode":"\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\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 != \"\" {","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/unionlabs/union/blob/031785bb6dc6b957c624e62bc64c184409c97d7b/uniond/cmd/uniond/cmd/testnet.go#L208-L244","documentation":"getCommandArgs requires appOpts.Get(server.KeyUserPubKey) to be a crypto.PubKey interface value (e.g., an ed25519.PubKey injected by the testnet key generation). A nil value or a non-PubKey type — notably a raw string or []byte from configuration — fails the assertion and panics.","triggerScenarios":"Programmatic testnet invocation without the flag wired; supplying the public key as a hex/base64 string in appOpts instead of a constructed crypto.PubKey; flag binding removed by a custom command wrapper.","commonSituations":"Embedding the testnet runner in tests or tooling; loading options from JSON/viper files where everything deserializes to primitives; refactors that skip server.AddTestnetFlags-style wiring.","solutions":["Use the `uniond testnet` CLI path where the generated validator key is inserted as a crypto.PubKey","When setting options yourself, construct the concrete type first (e.g., ed25519.PubKey{Key: bytes}) before viper.Set","Convert any string-encoded pubkey at the boundary — never rely on the assertion to accept it","In forks, return an error naming the missing key instead of panicking"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// The pubkey must be a constructed crypto.PubKey, never a string from config\npubKey := ed25519.PubKey{Key: mustHexDecode(pubKeyHex)}\nvpr.Set(server.KeyUserPubKey, pubKey)","typeGuard":"func optPubKey(appOpts servertypes.AppOptions, key string) (crypto.PubKey, bool) {\n\tv, ok := appOpts.Get(key).(crypto.PubKey)\n\treturn v, ok\n}","tryCatchPattern":null,"preventionTips":["Convert hex/base64 pubkey strings into crypto.PubKey values at the option boundary","Run testnet through the CLI where key generation inserts the typed value","Assert option presence in test setup before building the app","A nil (missing) option fails the assertion the same way as a wrong type — set defaults explicitly"],"tags":["cosmos-sdk","testnet","flags","crypto","panic","golang"],"backgroundTag":null,"analyzedSha":"031785bb6dc6b957c624e62bc64c184409c97d7b","analyzedAt":"2026-08-16T06:24:09.996Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}