kataras/iris · error
expected [%d] bindings (input parameters) but got [%d] Funct
Error message
expected [%d] bindings (input parameters) but got [%d] Function: - %s Expected:%s Missing:%s
What it means
hero resolves each of a handler function's input parameters into a binding backed by a dependency. If the number of resolved bindings does not equal the number of function inputs, some parameter could not be matched to any registered dependency (or payload binding), so hero panics with a detailed expected/missing report to prevent a broken handler from ever serving requests.
Source
Thrown at hero/binding.go:287
for i, in := range inputs {
pos := i + 1
typName := in.String()
expectedInputs += fmt.Sprintf("\n - [%d] %s", pos, typName)
found := false
for _, b := range bindings {
if b.Input.Index == i {
found = true
break
}
}
if !found {
missingInputs += fmt.Sprintf("\n - [%d] %s", pos, typName)
}
}
fnName := context.HandlerName(fn)
panic(fmt.Sprintf("expected [%d] bindings (input parameters) but got [%d]\nFunction:\n - %s\nExpected:%s\nMissing:%s",
expected, got, fnName, expectedInputs, missingInputs))
}
return bindings
}
func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, markExportedFieldsAsRequired bool, disablePayloadAutoBinding, enableStructDependents bool, matchDependency DependencyMatcher, paramsCount int, sorter Sorter) (bindings []*binding) {
typ := indirectType(v.Type())
if typ.Kind() != reflect.Struct {
panic(fmt.Sprintf("bindings: unresolved: not a struct type: %#+v", v))
}
// get bindings from any struct's non zero values first, including unexported.
elem := reflect.Indirect(v)
nonZero := lookupNonZeroFieldValues(elem)
for _, f := range nonZero {
// fmt.Printf("Controller [%s] | NonZero | Field Index: %v | Field Type: %s\n", typ, f.Index, f.Type)
bindings = append(bindings, &binding{View on GitHub (pinned to 7bedaf55a0)
Solutions
- Read the Missing list in the panic: it names each unmatched input parameter type; register a dependency for each, e.g. c.Container.Register(func() *Service { return NewService() }).
- Register the dependency with Container.Register before calling Container.Handler.
- If the parameter should come from the request payload, ensure it is a supported payload type (struct/slice/ptr) and that payload auto-binding is not disabled via hero.DisablePayloadAutoBinding.
- Check that the dependency's return type exactly matches the handler's parameter type (pointer vs value, interface vs concrete).
- Use hero's Reporter for a detailed diagnostic of what could be bound.
- Mark truly optional/unmatched params differently or remove them from the handler signature.
Example fix
// before
func handler(svc *MyService) {} // panics: *MyService not bindable
// after
container.Register(func() *MyService { return NewMyService() })
app.Party("/").ConfigureContainer(container).Handler(handler) Defensive patterns
Strategy: validation
Validate before calling
// sanity check before registering the handler
rv := reflect.TypeOf(handler)
for i := 0; i < rv.NumIn(); i++ {
in := rv.In(i)
if !container.HasDependencyFor(in) { // or check against your registered deps
log.Printf("warning: handler param %s has no registered dependency", in)
}
} Type guard
func canBindInputs(fn any, deps ...any) bool {
t := reflect.TypeOf(fn)
if t == nil || t.Kind() != reflect.Func { return false }
provided := map[reflect.Type]bool{}
for _, d := range deps { provided[reflect.TypeOf(d)] = true }
for i := 0; i < t.NumIn(); i++ {
if !provided[t.In(i)] { return false }
}
return true
} Try / catch
func safeRegister(h any) (ok bool) {
defer func() {
if r := recover(); r != nil {
if s, isStr := r.(string); isStr && strings.Contains(s, "bindings") {
log.Printf("handler binding failed: %s", s)
} else { panic(r) }
}
}()
container.Handler(h)
return true
} Prevention
- Register every service dependency before wiring handlers.
- Match dependency return types exactly to handler parameter types (pointer vs value).
- Run container.Report(os.Stdout) at startup to catch missing bindings early.
- Avoid disabling payload auto-binding unless all payload params are explicitly handled.
- Keep handler signatures limited to types hero knows how to bind.
When it happens
Trigger: Registering a handler whose parameters' types are not covered by Container.Register dependency functions or built-in bindings (e.g. a custom *Service parameter with no matching dependency, an unexported/unsupported param type), or registering a dependency whose return type does not exactly match the parameter type under the default matcher, or disabling payload auto-binding while the handler expects a request payload struct.
Common situations: Forgetting Container.Register for a custom service type; a dependency registered for an interface type while the handler asks for the concrete type (or vice versa); renaming a service type after refactor; typo in generic type parameters; handler takes a context-independent param that hero cannot infer (like *http.Request wrappers); missing Singleton dependency after DI refactor.
Related errors
- bindings: unresolved: no a func type: %#+v
- bindings: unresolved: not a struct type: %#+v
- MarkExportedFieldsAsRequired is true and at least one of str
- bad value: nil: %T
- bad value: could not resolve a dependency from: %#+v
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/a7de5a6415cb57ae.
Report an issue: GitHub.