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

  1. 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() }).
  2. Register the dependency with Container.Register before calling Container.Handler.
  3. 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.
  4. Check that the dependency's return type exactly matches the handler's parameter type (pointer vs value, interface vs concrete).
  5. Use hero's Reporter for a detailed diagnostic of what could be bound.
  6. 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

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


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/a7de5a6415cb57ae. Report an issue: GitHub.