{"record":{"id":"dee91821fa6a1554","repo":"kataras/iris","slug":"bindings-unresolved-not-a-struct-type-v","errorCode":null,"errorMessage":"bindings: unresolved: not a struct type: %#+v","messagePattern":"bindings: unresolved: not a struct type: %#\\+v","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hero/binding.go","lineNumber":297,"sourceCode":"\t\t\t}\n\n\t\t\tif !found {\n\t\t\t\tmissingInputs += fmt.Sprintf(\"\\n  - [%d] %s\", pos, typName)\n\t\t\t}\n\t\t}\n\n\t\tfnName := context.HandlerName(fn)\n\t\tpanic(fmt.Sprintf(\"expected [%d] bindings (input parameters) but got [%d]\\nFunction:\\n  - %s\\nExpected:%s\\nMissing:%s\",\n\t\t\texpected, got, fnName, expectedInputs, missingInputs))\n\t}\n\n\treturn bindings\n}\n\nfunc getBindingsForStruct(v reflect.Value, dependencies []*Dependency, markExportedFieldsAsRequired bool, disablePayloadAutoBinding, enableStructDependents bool, matchDependency DependencyMatcher, paramsCount int, sorter Sorter) (bindings []*binding) {\n\ttyp := indirectType(v.Type())\n\tif typ.Kind() != reflect.Struct {\n\t\tpanic(fmt.Sprintf(\"bindings: unresolved: not a struct type: %#+v\", v))\n\t}\n\n\t// get bindings from any struct's non zero values first, including unexported.\n\telem := reflect.Indirect(v)\n\tnonZero := lookupNonZeroFieldValues(elem)\n\tfor _, f := range nonZero {\n\t\t// fmt.Printf(\"Controller [%s] | NonZero | Field Index: %v | Field Type: %s\\n\", typ, f.Index, f.Type)\n\t\tbindings = append(bindings, &binding{\n\t\t\tDependency: newDependency(elem.FieldByIndex(f.Index).Interface(), disablePayloadAutoBinding, enableStructDependents, nil),\n\t\t\tInput:      newStructFieldInput(f),\n\t\t})\n\t}\n\n\tfields, stateless := lookupFields(elem, true, true, nil)\n\tn := len(fields)\n\n\tif n > 1 && sorter != nil {\n\t\tsort.Slice(fields, func(i, j int) bool {","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/hero/binding.go#L279-L315","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a struct or pointer-to-struct to the controller/struct registration API: container.Controller(new(MyController)) or hero.Struct(MyStruct{}).","Check the dynamic type of the value: reflect.Indirect(reflect.TypeOf(v)).Kind() must be reflect.Struct.","If the value is a map/config, convert it into a proper struct before registering.","If it is an interface, assert to the concrete struct type first.","Remove the pointer/slice wrapper if it does not point to a struct."],"exampleFix":"// before\ncontainer.Controller(myMap) // map is not a struct\n// after\ncontainer.Controller(new(MyController)) // pointer to struct","handlingStrategy":"type-guard","validationCode":"func assertStruct(v any) error {\n    if v == nil { return fmt.Errorf(\"nil value\") }\n    t := reflect.Indirect(reflect.TypeOf(v))\n    if t.Kind() != reflect.Struct { return fmt.Errorf(\"%T is not a struct\", v) }\n    return nil\n}\n// before registration: if err := assertStruct(ctrl); err != nil { log.Fatal(err) }","typeGuard":"func isStructValue(v any) bool {\n    if v == nil { return false }\n    return reflect.Indirect(reflect.TypeOf(v)).Kind() == reflect.Struct\n}","tryCatchPattern":"func safeController(c any) (ok bool) {\n    defer func() {\n        if r := recover(); r != nil {\n            if s, isStr := r.(string); isStr && strings.Contains(s, \"not a struct type\") {\n                log.Printf(\"controller registration failed: %s\", s)\n            } else { panic(r) }\n        }\n    }()\n    container.Controller(c)\n    return true\n}","preventionTips":["Always register pointers to structs (new(MyController)) with controller APIs.","Guard that dynamic types behind interfaces are structs before registration.","Never pass maps, slices or funcs to struct-registration APIs.","Add a startup test that constructs all controllers to surface bad types in CI."],"tags":["go","reflection","dependency-injection","panic","struct-registration"],"backgroundTag":"non-struct-binding-value","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}