{"record":{"id":"caa61c286009da62","repo":"slackhq/nebula","slug":"failed-to-cast-command","errorCode":null,"errorMessage":"failed to cast command","messagePattern":"failed to cast command","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sshd/command.go","lineNumber":80,"sourceCode":"\n\tcmds := make([]string, 0)\n\tfor _, l := range allCommands(c) {\n\t\tcmds = append(cmds, fmt.Sprintf(\"%s - %s\", l.Name, l.ShortDescription))\n\t}\n\n\tsort.Strings(cmds)\n\t_ = w.Write(strings.Join(cmds, \"\\n\") + \"\\n\\n\")\n}\n\nfunc lookupCommand(c *radix.Tree, sCmd string) (*Command, error) {\n\tcmd, ok := c.Get(sCmd)\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\n\tcommand, ok := cmd.(*Command)\n\tif !ok {\n\t\treturn nil, errors.New(\"failed to cast command\")\n\t}\n\n\treturn command, nil\n}\n\nfunc matchCommand(c *radix.Tree, cmd string) []string {\n\tcmds := make([]string, 0)\n\tc.WalkPrefix(cmd, func(found string, v any) bool {\n\t\tcmds = append(cmds, found)\n\t\treturn false\n\t})\n\tsort.Strings(cmds)\n\treturn cmds\n}\n\nfunc allCommands(c *radix.Tree) []*Command {\n\tcmds := make([]*Command, 0)\n\tc.WalkPrefix(\"\", func(found string, v any) bool {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/sshd/command.go#L62-L98","documentation":"The nebula sshd stores commands in a radix tree as interface{} values. lookupCommand retrieves a value by name and asserts it is *Command; if the stored value is of any other type, it returns \"failed to cast command\" instead of panicking. This guards against registry entries that violate the *Command contract.","triggerScenarios":"A value registered into the sshd command radix tree (e.g., via tree.Insert) that is not a *Command is looked up by lookupCommand, so the `cmd.(*Command)` type assertion fails.","commonSituations":"Custom sshd command registration code inserting the wrong concrete type; refactors that change the command type stored in the tree; test code registering stubs into the command tree.","solutions":["Inspect the code path that inserts commands into the sshd radix tree and ensure it always stores *Command values","Fix the registration site so the concrete type implements/converts to *Command","Check for multiple conflicting registrations of the same command name from different init paths"],"exampleFix":"// before\ntree.Insert(name, myCommandStruct{})\n// after\ntree.Insert(name, &Command{\n    Name: name,\n    ShortHelp: \"...\",\n    Run: myRunFunc,\n})","handlingStrategy":"type-guard","validationCode":"if v, ok := tree.Get(name); !ok {\n    return nil, nil // command not found\n}","typeGuard":"command, ok := cmd.(*Command)\nif !ok {\n    return nil, errors.New(\"failed to cast command\")\n}","tryCatchPattern":"command, err := lookupCommand(tree, name)\nif err != nil {\n    l.WithError(err).WithField(\"name\", name).Error(\"command lookup failed\")\n    return err\n}","preventionTips":["Only insert *Command values into the sshd radix tree","Centralize command registration in one function","Add a startup assertion that walks the tree asserting all values are *Command","Review refactors that change the stored command type"],"tags":["nebula","sshd","type-assertion","go"],"backgroundTag":"type-assertion-failed","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}