gofiber/fiber · error
multiple binding_source tags found on struct %s
Error message
multiple binding_source tags found on struct %s
What it means
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.
Source
Thrown at bind.go:466
type cachedPrecedence struct {
err error
sources []bindSource
}
var bindingPrecedenceCache sync.Map // map[reflect.Type]cachedPrecedence
func getBindingPrecedence(t reflect.Type) ([]bindSource, error) {
if cached, ok := bindingPrecedenceCache.Load(t); ok {
if cp, ok := cached.(cachedPrecedence); ok {
return cp.sources, cp.err
}
}
var precedence []bindSource
var tagFound bool
for i := range t.NumField() {
if tag := t.Field(i).Tag.Get("binding_source"); tag != "" {
if tagFound {
err := fmt.Errorf("multiple binding_source tags found on struct %s", t.Name())
bindingPrecedenceCache.Store(t, cachedPrecedence{err: err, sources: nil})
return nil, err
}
tagFound = true
parts := strings.SplitSeq(tag, ",")
for p := range parts {
sourceName := strings.TrimSpace(p)
if sourceName == "" {
continue
}
var source bindSource
switch sourceName {
case "uri":
source = sourceURI
case "body":
source = sourceBody
case "query":View on GitHub (pinned to 9a4c7e57fe)
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.
Example fix
// before
type LoginReq struct {
Email string `binding_source:"query"`
Token string `binding_source:"header"`
}
// after — one tag, sources in precedence order
type LoginReq struct {
Email string `binding_source:"uri,query"`
Token string
} Defensive patterns
Strategy: validation
Validate before calling
// At startup, bind a zero value of each request struct to surface tag errors early.
func validateBindStructs(types []any) error {
for _, t := range types {
if err := app.Bind().All(t); err != nil {
if strings.Contains(err.Error(), "binding_source") {
return fmt.Errorf("bad struct %T: %w", t, err)
}
}
}
return nil
} Try / catch
if err := c.Bind().All(&req); err != nil {
if strings.Contains(err.Error(), "multiple binding_source tags") {
// struct has >1 binding_source tag — fix the struct definition
return fiber.NewError(fiber.StatusBadRequest, "bad request schema")
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- unknown binding_source %q
- unsupported value type: %T
- binder: custom binder not found, please be sure to enter the
- log: context tag name and function are required
- logger: tag name and function are required
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/36e8ef1f7d27c4d1.json.
Report an issue: GitHub.