kataras/iris · error

bindings: unresolved: not a struct type: %#+v

Error message

bindings: unresolved: not a struct type: %#+v

What it means

getBindingsForStruct builds bindings from a struct's fields, so it first asserts that the (indirected) value's kind is reflect.Struct. When it is given a non-struct value — for example a map, slice, func or basic type wrapped in reflect.Value — it panics with 'bindings: unresolved: not a struct type' to stop struct-dependent resolution early.

Source

Thrown at hero/binding.go:297

			}

			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{
			Dependency: newDependency(elem.FieldByIndex(f.Index).Interface(), disablePayloadAutoBinding, enableStructDependents, nil),
			Input:      newStructFieldInput(f),
		})
	}

	fields, stateless := lookupFields(elem, true, true, nil)
	n := len(fields)

	if n > 1 && sorter != nil {
		sort.Slice(fields, func(i, j int) bool {

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Pass a struct or pointer-to-struct to the controller/struct registration API: container.Controller(new(MyController)) or hero.Struct(MyStruct{}).
  2. Check the dynamic type of the value: reflect.Indirect(reflect.TypeOf(v)).Kind() must be reflect.Struct.
  3. If the value is a map/config, convert it into a proper struct before registering.
  4. If it is an interface, assert to the concrete struct type first.
  5. Remove the pointer/slice wrapper if it does not point to a struct.

Example fix

// before
container.Controller(myMap) // map is not a struct
// after
container.Controller(new(MyController)) // pointer to struct
Defensive patterns

Strategy: type-guard

Validate before calling

func assertStruct(v any) error {
    if v == nil { return fmt.Errorf("nil value") }
    t := reflect.Indirect(reflect.TypeOf(v))
    if t.Kind() != reflect.Struct { return fmt.Errorf("%T is not a struct", v) }
    return nil
}
// before registration: if err := assertStruct(ctrl); err != nil { log.Fatal(err) }

Type guard

func isStructValue(v any) bool {
    if v == nil { return false }
    return reflect.Indirect(reflect.TypeOf(v)).Kind() == reflect.Struct
}

Try / catch

func safeController(c any) (ok bool) {
    defer func() {
        if r := recover(); r != nil {
            if s, isStr := r.(string); isStr && strings.Contains(s, "not a struct type") {
                log.Printf("controller registration failed: %s", s)
            } else { panic(r) }
        }
    }()
    container.Controller(c)
    return true
}

Prevention

When it happens

Trigger: Passing a non-struct value to hero.Struct / Container.Controller (which route through makeStruct -> fromStructValueOrDependentStructValue -> getBindingsForStruct), or registering a dependency whose resolved value is expected to be treated as a struct but is actually e.g. a pointer to a non-struct, a map[string]any, or a func.

Common situations: Calling container.Controller with a value instead of a struct/pointer-to-struct; registering a map-based config object as a dependency and expecting field injection; typos like &someSlice; upgrading versions where the API now requires a struct pointer; passing an interface variable whose dynamic kind is not struct.

Related errors


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