beego/beego · critical
{controllerType.String()} is not implemented ControllerInter
Error message
{controllerType.String()} is not implemented ControllerInterface What it means
The receiver type resolved from the method expression must implement web.ControllerInterface — in practice every beego controller gets this by embedding web.Controller. getReflectTypeAndMethod instantiates the type with reflect.New and type-asserts to ControllerInterface; on failure it panics with '<type> is not implemented ControllerInterface' at registration time.
Source
Thrown at server/web/router.go:631
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)
// Get add get method
// usage:
//
// Get("/", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegister) Get(pattern string, f HandleFunc) {
p.AddMethod("get", pattern, f)
}
View on GitHub (pinned to 939cfde380)
Solutions
- Embed web.Controller in the struct: type Api struct { web.Controller }
- If you cannot embed it, use beego.Get(pattern, func(ctx *context.Context)) instead of the Ctrl* method-expression API
- Re-run after embedding to confirm the registration panic is gone
Example fix
// before
type Api struct{}
func (a Api) Ping() {}
web.CtrlGet("/ping", Api.Ping)
// after
type Api struct{ web.Controller }
func (a Api) Ping() { a.Ctx.Output.Body([]byte("pong")) }
web.CtrlGet("/ping", Api.Ping) Defensive patterns
Strategy: type-guard
Validate before calling
var _ web.ControllerInterface = (*MyController)(nil) // compile-time check at package level
Type guard
type Controller interface{ web.ControllerInterface }
func RegisterCtrl[T Controller](pattern string, m func(T)) {
// T guaranteed to implement ControllerInterface at compile time
}
RegisterCtrl("/ping", MyController.Ping) // fails to compile if MyController lacks web.Controller Try / catch
defer func() { if r := recover(); r != nil { log.Fatalf("controller must embed web.Controller: %v", r) } }() Prevention
- Start every controller with `struct { web.Controller }` as boilerplate
- Add the `var _ web.ControllerInterface = (*X)(nil)` assertion next to each controller
- Reserve beego.Get/Router+closure style for handlers that cannot embed Controller
When it happens
Trigger: web.CtrlGet("/x", Api.Ping) where type Api struct{} does not embed web.Controller (and does not implement Init/Prepare/... itself); using a plain struct with exported parameterless methods in the Ctrl* API.
Common situations: Reusing a service/domain struct as a 'controller'; writing a minimal handler struct for beego v2 without embedding the Controller; partially migrating controllers that previously satisfied an older interface.
Related errors
- '{colon[1]}' method doesn't exist in the controller {t.Name(
- method mapping format is invalid
- {v} is an invalid method mapping. Method doesn't exist {m}
- not support http method: {method}
- not a method
AI-assisted analysis of beego/beego@939cfde380 (2026-08-15).
Data as JSON: /api/errors/04fddb74776f541b.
Report an issue: GitHub.