{"record":{"id":"e4a892f873b8cf15","repo":"beego/beego","slug":"controllertype-string-has-no-method-method","errorCode":null,"errorMessage":"{controllerType.String()} has no method {method}","messagePattern":"(.+?) has no method (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/web/router.go","lineNumber":621,"sourceCode":"\n\tmethod = funcNameSli[lFuncSli-1]\n\tif len(method) == 0 {\n\t\tpanic(\"method name is empty\")\n\t} else if method[0] > 96 || method[0] < 65 {\n\t\tpanic(fmt.Sprintf(\"%s is not a public method\", method))\n\t}\n\n\t// check only one param which is the method receiver\n\tif numIn := funcType.NumIn(); numIn != 1 {\n\t\tpanic(\"invalid number of param in\")\n\t}\n\n\tcontrollerType = funcType.In(0)\n\n\t// check controller has the method\n\t_, exists := controllerType.MethodByName(method)\n\tif !exists {\n\t\tpanic(controllerType.String() + \" has no method \" + method)\n\t}\n\n\t// check the receiver implement ControllerInterface\n\tif controllerType.Kind() == reflect.Ptr {\n\t\tcontrollerType = controllerType.Elem()\n\t}\n\tcontroller := reflect.New(controllerType)\n\t_, ok := controller.Interface().(ControllerInterface)\n\tif !ok {\n\t\tpanic(controllerType.String() + \" is not implemented ControllerInterface\")\n\t}\n\n\treturn\n}\n\n// HandleFunc define how to process the request\ntype HandleFunc func(ctx *beecontext.Context)\n","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/beego/beego/blob/939cfde380bb9f15844ad633b84f037f7da21584/server/web/router.go#L603-L639","documentation":"getReflectTypeAndMethod extracted the method name from the func's runtime symbol and the controller type from the expression's single In(0) parameter, but reflect MethodByName on that controller type does not find a method with that name. The func value and its receiver type are inconsistent — something that a plain Type.Method expression can never produce, so the argument was manufactured indirectly.","triggerScenarios":"Passing a method value bound through an embedded field or a wrapper created with reflect.MakeFunc that carries a method-like name; stale generated/duplicated controller code where the method expression and the receiver type come from different versions of the type after a partial rebuild.","commonSituations":"Weird reflection-based handler registries wrapping controller methods; incremental compile artifacts after renaming a controller method; vendored forks where a method was renamed upstream.","solutions":["Rewrite the registration as a plain method expression: web.CtrlGet(\"/x\", MyController.Ping)","go clean -cache (or rebuild) if symbols look stale after renames","Make sure the method is declared directly on the controller type passed to the route, not only on an embedded struct"],"exampleFix":"// before\nweb.CtrlGet(\"/x\", reflectWrapperOf(MyController)) // indirect func value\n\n// after\nweb.CtrlGet(\"/x\", MyController.Ping)","handlingStrategy":"validation","validationCode":"func methodBelongsToController(f interface{}) bool {\n    ft := reflect.TypeOf(f)\n    fo := runtime.FuncForPC(reflect.ValueOf(f).Pointer())\n    if fo == nil || ft.NumIn() != 1 { return false }\n    name := strings.Split(fo.Name(), \".\")\n    _, ok := ft.In(0).MethodByName(name[len(name)-1])\n    return ok\n}","typeGuard":"// a plain method expression is always self-consistent; guard rejects indirect wrappers\nfunc directExpr[T any](_ func(T)) {}","tryCatchPattern":"defer func() { if r := recover(); r != nil { log.Fatalf(\"registration: %v — pass MyController.Method directly\", r) } }()","preventionTips":["Never wrap or synthesize handler funcs with reflect/unsafe before Ctrl* registration","go clean -cache after renaming controller methods or switching branches","Keep controllers and their route registrations in the same module version"],"tags":["go","beego","router","reflection","panic"],"backgroundTag":null,"analyzedSha":"939cfde380bb9f15844ad633b84f037f7da21584","analyzedAt":"2026-08-15T17:22:06.535Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}