{"record":{"id":"04fddb74776f541b","repo":"beego/beego","slug":"controllertype-string-is-not-implemented-contr","errorCode":null,"errorMessage":"{controllerType.String()} is not implemented ControllerInterface","messagePattern":"(.+?) is not implemented ControllerInterface","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/web/router.go","lineNumber":631,"sourceCode":"\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\n// Get add get method\n// usage:\n//\n//\tGet(\"/\", func(ctx *context.Context){\n//\t      ctx.Output.Body(\"hello world\")\n//\t})\nfunc (p *ControllerRegister) Get(pattern string, f HandleFunc) {\n\tp.AddMethod(\"get\", pattern, f)\n}\n","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/beego/beego/blob/939cfde380bb9f15844ad633b84f037f7da21584/server/web/router.go#L613-L649","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ntype Api struct{}\nfunc (a Api) Ping() {}\nweb.CtrlGet(\"/ping\", Api.Ping)\n\n// after\ntype Api struct{ web.Controller }\nfunc (a Api) Ping() { a.Ctx.Output.Body([]byte(\"pong\")) }\nweb.CtrlGet(\"/ping\", Api.Ping)","handlingStrategy":"type-guard","validationCode":"var _ web.ControllerInterface = (*MyController)(nil) // compile-time check at package level","typeGuard":"type Controller interface{ web.ControllerInterface }\n\nfunc RegisterCtrl[T Controller](pattern string, m func(T)) {\n    // T guaranteed to implement ControllerInterface at compile time\n}\nRegisterCtrl(\"/ping\", MyController.Ping) // fails to compile if MyController lacks web.Controller","tryCatchPattern":"defer func() { if r := recover(); r != nil { log.Fatalf(\"controller must embed web.Controller: %v\", r) } }()","preventionTips":["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"],"tags":["go","beego","router","controller","interface","panic"],"backgroundTag":null,"analyzedSha":"939cfde380bb9f15844ad633b84f037f7da21584","analyzedAt":"2026-08-15T17:22:06.535Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}