{"id":"36e8ef1f7d27c4d1","repo":"gofiber/fiber","slug":"multiple-binding-source-tags-found-on-struct-s","errorCode":null,"errorMessage":"multiple binding_source tags found on struct %s","messagePattern":"multiple binding_source tags found on struct (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"bind.go","lineNumber":466,"sourceCode":"type cachedPrecedence struct {\n\terr     error\n\tsources []bindSource\n}\n\nvar bindingPrecedenceCache sync.Map // map[reflect.Type]cachedPrecedence\n\nfunc getBindingPrecedence(t reflect.Type) ([]bindSource, error) {\n\tif cached, ok := bindingPrecedenceCache.Load(t); ok {\n\t\tif cp, ok := cached.(cachedPrecedence); ok {\n\t\t\treturn cp.sources, cp.err\n\t\t}\n\t}\n\tvar precedence []bindSource\n\tvar tagFound bool\n\tfor i := range t.NumField() {\n\t\tif tag := t.Field(i).Tag.Get(\"binding_source\"); tag != \"\" {\n\t\t\tif tagFound {\n\t\t\t\terr := fmt.Errorf(\"multiple binding_source tags found on struct %s\", t.Name())\n\t\t\t\tbindingPrecedenceCache.Store(t, cachedPrecedence{err: err, sources: nil})\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ttagFound = true\n\n\t\t\tparts := strings.SplitSeq(tag, \",\")\n\t\t\tfor p := range parts {\n\t\t\t\tsourceName := strings.TrimSpace(p)\n\t\t\t\tif sourceName == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvar source bindSource\n\t\t\t\tswitch sourceName {\n\t\t\t\tcase \"uri\":\n\t\t\t\t\tsource = sourceURI\n\t\t\t\tcase \"body\":\n\t\t\t\t\tsource = sourceBody\n\t\t\t\tcase \"query\":","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/bind.go#L448-L484","documentation":"Returned by getBindingPrecedence (bind.go:466) when reflect-scanning a struct finds more than one field carrying a `binding_source` struct tag. The binding_source tag customizes the order Bind().All() consults sources (uri/body/query/header/cookie); the design allows exactly one such tag per struct, with multiple sources comma-separated inside it. Two tags create an ambiguous precedence, so the whole bind is rejected and the error cached per type.","triggerScenarios":"Defining a struct like `type Req struct { A string `binding_source:\"query\"`; B string `binding_source:\"header\"` }` and passing it to Bind().All(). The reflect scan sees two tagged fields and errors before any binding happens.","commonSituations":"Refactoring a bind struct and adding a second binding_source tag instead of combining sources; copy-paste of tagged fields; misunderstanding that multiple sources go in one tag (comma-separated).","solutions":["Use a single binding_source tag listing all sources in precedence order, e.g. `binding_source:\"uri,query,body\"`.","Remove the duplicate tag and choose which field drives precedence.","Run a startup sanity check that binds a zero value of each request struct to surface this before traffic."],"exampleFix":"// before\ntype LoginReq struct {\n    Email string `binding_source:\"query\"`\n    Token string `binding_source:\"header\"`\n}\n\n// after — one tag, sources in precedence order\ntype LoginReq struct {\n    Email string `binding_source:\"uri,query\"`\n    Token string\n}","handlingStrategy":"validation","validationCode":"// At startup, bind a zero value of each request struct to surface tag errors early.\nfunc validateBindStructs(types []any) error {\n    for _, t := range types {\n        if err := app.Bind().All(t); err != nil {\n            if strings.Contains(err.Error(), \"binding_source\") {\n                return fmt.Errorf(\"bad struct %T: %w\", t, err)\n            }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := c.Bind().All(&req); err != nil {\n    if strings.Contains(err.Error(), \"multiple binding_source tags\") {\n        // struct has >1 binding_source tag — fix the struct definition\n        return fiber.NewError(fiber.StatusBadRequest, \"bad request schema\")\n    }\n    return err\n}","preventionTips":["Use exactly one binding_source tag per struct; combine sources comma-separated.","Add a unit test that binds a sample struct so tag errors surface before production.","Review struct tags during code review when adding new request types."],"tags":["binding","struct-tag","validation","reflection"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}