beego/beego · critical
{controllerType.String()} has no method {method}
Error message
{controllerType.String()} has no method {method} What it means
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.
Source
Thrown at server/web/router.go:621
method = funcNameSli[lFuncSli-1]
if len(method) == 0 {
panic("method name is empty")
} else if method[0] > 96 || method[0] < 65 {
panic(fmt.Sprintf("%s is not a public method", method))
}
// check only one param which is the method receiver
if numIn := funcType.NumIn(); numIn != 1 {
panic("invalid number of param in")
}
controllerType = funcType.In(0)
// check controller has the method
_, exists := controllerType.MethodByName(method)
if !exists {
panic(controllerType.String() + " has no method " + method)
}
// check the receiver implement ControllerInterface
if controllerType.Kind() == reflect.Ptr {
controllerType = controllerType.Elem()
}
controller := reflect.New(controllerType)
_, ok := controller.Interface().(ControllerInterface)
if !ok {
panic(controllerType.String() + " is not implemented ControllerInterface")
}
return
}
// HandleFunc define how to process the request
type HandleFunc func(ctx *beecontext.Context)
View on GitHub (pinned to 939cfde380)
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
Example fix
// before
web.CtrlGet("/x", reflectWrapperOf(MyController)) // indirect func value
// after
web.CtrlGet("/x", MyController.Ping) Defensive patterns
Strategy: validation
Validate before calling
func methodBelongsToController(f interface{}) bool {
ft := reflect.TypeOf(f)
fo := runtime.FuncForPC(reflect.ValueOf(f).Pointer())
if fo == nil || ft.NumIn() != 1 { return false }
name := strings.Split(fo.Name(), ".")
_, ok := ft.In(0).MethodByName(name[len(name)-1])
return ok
} Type guard
// a plain method expression is always self-consistent; guard rejects indirect wrappers
func directExpr[T any](_ func(T)) {} Try / catch
defer func() { if r := recover(); r != nil { log.Fatalf("registration: %v — pass MyController.Method directly", r) } }() Prevention
- 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
When it happens
Trigger: 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.
Common situations: Weird reflection-based handler registries wrapping controller methods; incremental compile artifacts after renaming a controller method; vendored forks where a method was renamed upstream.
Related errors
- '{colon[1]}' method doesn't exist in the controller {t.Name(
- not a method
- cannot find the method
- %s is not a public method
- invalid number of param in
AI-assisted analysis of beego/beego@939cfde380 (2026-08-15).
Data as JSON: /api/errors/e4a892f873b8cf15.
Report an issue: GitHub.