{"id":"b5de9eb1ce770542","repo":"gin-gonic/gin","slug":"bind-struct-can-not-be-a-pointer-example-use-g","errorCode":null,"errorMessage":"Bind struct can not be a pointer. Example:\n\tUse: gin.Bind(Struct{}) instead of gin.Bind(&Struct{})\n","messagePattern":"Bind struct can not be a pointer\\. Example:\n\tUse: gin\\.Bind\\(Struct(.+?)\\) instead of gin\\.Bind\\(&Struct(.+?)\\)\n","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"utils.go","lineNumber":32,"sourceCode":"\t\"runtime\"\n\t\"strings\"\n\t\"unicode\"\n)\n\n// BindKey indicates a default bind key.\nconst BindKey = \"_gin-gonic/gin/bindkey\"\n\n// localhostIP indicates the default localhost IP address.\nconst localhostIP = \"127.0.0.1\"\n\n// localhostIPv6 indicates the default localhost IPv6 address.\nconst localhostIPv6 = \"::1\"\n\n// Bind is a helper function for given interface object and returns a Gin middleware.\nfunc Bind(val any) HandlerFunc {\n\tvalue := reflect.ValueOf(val)\n\tif value.Kind() == reflect.Ptr {\n\t\tpanic(`Bind struct can not be a pointer. Example:\n\tUse: gin.Bind(Struct{}) instead of gin.Bind(&Struct{})\n`)\n\t}\n\ttyp := value.Type()\n\n\treturn func(c *Context) {\n\t\tobj := reflect.New(typ).Interface()\n\t\tif c.Bind(obj) == nil {\n\t\t\tc.Set(BindKey, obj)\n\t\t}\n\t}\n}\n\n// WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware.\nfunc WrapF(f http.HandlerFunc) HandlerFunc {\n\treturn func(c *Context) {\n\t\tf(c.Writer, c.Request)\n\t}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/gin-gonic/gin/blob/34dac209ffb6ef85cc78c5d217bbb7ad001d68fd/utils.go#L14-L50","documentation":"Thrown by gin.Bind in utils.go:32 when the value passed to Bind is a reflect.Pointer. gin.Bind is a middleware factory: it records the struct TYPE so that, on each request, it can reflect.New(typ) a fresh zero-value to deserialize into. Passing &Struct{} would cause every request to share the same instance, so the function refuses a pointer and asks for the value form. The message shows the intended usage: gin.Bind(Struct{}) not gin.Bind(&Struct{}).","triggerScenarios":"Calling router.Use(gin.Bind(&LoginRequest{})) or gin.Bind(&User{}) at router setup time. Any time the argument to gin.Bind is an address-of expression rather than a struct literal.","commonSituations":"Migrating from c.ShouldBind(&obj) (where a pointer IS correct at call site) to the Bind middleware factory and passing the pointer out of habit; copy-pasting a struct literal that already had '&' in front; reading examples for the wrong Bind API.","solutions":["Pass the struct by value: gin.Bind(LoginRequest{}). Bind records the type and allocates a fresh pointer per request internally.","If you need binding but not as middleware, use c.ShouldBind(&obj) inside the handler instead of gin.Bind.","Double-check you are calling gin.Bind (package-level middleware factory) and not c.ShouldBind / c.Bind (per-request methods on Context) — the conventions differ."],"exampleFix":"// before\nrouter.Use(gin.Bind(&LoginRequest{})) // panics: pointer not allowed\n\n// after — pass by value, Bind allocates per request\nrouter.Use(gin.Bind(LoginRequest{}))\n\n// alternative — bind inside the handler with a pointer (correct here)\nrouter.POST(\"/login\", func(c *gin.Context) {\n    var req LoginRequest\n    if err := c.ShouldBind(&req); err != nil { c.Status(400); return }\n    // ...\n})","handlingStrategy":"type-guard","validationCode":"// Verify the value passed to gin.Bind is not a pointer before calling it.\nfunc safeBind(v any) (gin.HandlerFunc, error) {\n    if reflect.ValueOf(v).Kind() == reflect.Ptr {\n        return nil, fmt.Errorf(\"gin.Bind requires a value, got pointer %T\", v)\n    }\n    return gin.Bind(v), nil\n}","typeGuard":"// isBindValue reports whether v is an acceptable argument for gin.Bind.\nfunc isBindValue(v any) bool {\n    return reflect.ValueOf(v).Kind() != reflect.Ptr\n}","tryCatchPattern":"func mustBind(v any) (mw gin.HandlerFunc) {\n    defer func() {\n        if r := recover(); r != nil {\n            panic(fmt.Errorf(\"gin.Bind(%T): %v\\nUse gin.Bind(Struct{}) not gin.Bind(&Struct{})\", v, r))\n        }\n    }()\n    return gin.Bind(v)\n}","preventionTips":["Memorise the rule: gin.Bind takes a VALUE (Struct{}), c.ShouldBind takes a POINTER (&obj).","Wrap every gin.Bind call site with a small helper that type-checks first.","Code-review any router.Use(gin.Bind(...)) for a stray '&' in front of the struct literal.","If the per-request pointer semantics are what you want, use c.ShouldBind(&obj) inside the handler instead of the middleware."],"tags":["binding","middleware","reflection","pointer","gin","startup-panic"],"analyzedSha":"34dac209ffb6ef85cc78c5d217bbb7ad001d68fd","analyzedAt":"2026-08-04T21:26:18.438Z","schemaVersion":2}