{"record":{"id":"29654b9fdfb518db","repo":"kataras/iris","slug":"markexportedfieldsasrequired-is-true-and-at-least","errorCode":null,"errorMessage":"MarkExportedFieldsAsRequired is true and at least one of struct's (%s) field was not binded to a dependency.\nFields length: %d, matched exported bindings length: %d.\nUse the Reporter for further details","messagePattern":"MarkExportedFieldsAsRequired is true and at least one of struct's \\((.+?)\\) field was not binded to a dependency\\.\nFields length: (.+?), matched exported bindings length: (.+?)\\.\nUse the Reporter for further details","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hero/binding.go","lineNumber":335,"sourceCode":"\t\t})\n\t}\n\n\tinputs := make([]reflect.Type, n)\n\tfor i := 0; i < n; i++ {\n\t\t// fmt.Printf(\"Controller [%s] | Field Index: %v | Field Type: %s\\n\", typ, fields[i].Index, fields[i].Type)\n\t\tinputs[i] = fields[i].Type\n\t}\n\n\texportedBindings := getBindingsFor(inputs, dependencies, disablePayloadAutoBinding, paramsCount)\n\n\t// fmt.Printf(\"Controller [%s] | Inputs length: %d vs Bindings length: %d | NonZero: %d | Stateless : %d\\n\",\n\t// \ttyp, n, len(exportedBindings), len(nonZero), stateless)\n\t// for i, b := range exportedBindings {\n\t// \tfmt.Printf(\"[%d] [Static=%v] %#+v\\n\", i, b.Dependency.Static, b.Dependency.OriginalValue)\n\t// }\n\n\tif markExportedFieldsAsRequired && len(exportedBindings) != n {\n\t\tpanic(fmt.Sprintf(\"MarkExportedFieldsAsRequired is true and at least one of struct's (%s) field was not binded to a dependency.\\nFields length: %d, matched exported bindings length: %d.\\nUse the Reporter for further details\", typ.String(), n, len(exportedBindings)))\n\t}\n\n\tif stateless == 0 && len(nonZero) >= len(exportedBindings) {\n\t\t// if we have not a single stateless and fields are defined then just return.\n\t\t// Note(@kataras): this can accept further improvements.\n\t\treturn\n\t}\n\n\t// get declared bindings from deps.\n\tbindings = append(bindings, exportedBindings...)\n\tfor _, binding := range bindings {\n\t\t// fmt.Printf(\"\"Controller [%s] | Binding: %s\\n\", typ, binding.String())\n\n\t\tif len(binding.Input.StructFieldIndex) == 0 {\n\t\t\t// set correctly the input's field index and name.\n\t\t\tf := fields[binding.Input.Index]\n\t\t\tbinding.Input.StructFieldIndex = f.Index\n\t\t\tbinding.Input.StructFieldName = f.Name","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/hero/binding.go#L317-L353","documentation":"When MarkExportedFieldsAsRequired (Container.RegisterDependency/struct registration with required exported fields) is enabled, hero insists that EVERY exported field of the struct resolves to a dependency binding. If len(exportedBindings) != len(fields), at least one exported field could not be matched, and hero panics telling you to use the Reporter for details.","triggerScenarios":"Enabling MarkExportedFieldsAsRequired (e.g. Container.Require or struct registration with markExported=true) while the struct has an exported field with no matching registered dependency — e.g. a field of type *DB, a time.Time, a basic type like string/int that no dependency provides, or a field that payload-binding intentionally skips.","commonSituations":"Turning on strict required-field mode in an existing codebase where one struct gained a new exported field that was never registered as a dependency; fields of primitive types that DI was never meant to fill; a dependency registered for an interface while the field is the concrete type; test fixtures using TestBindingsForStructMarkExportedFieldsAsRequred style setups missing one dependency.","solutions":["Register a dependency for every missing exported field type, e.g. container.Register(func() *DB { return db }).","Read the hero Reporter output (container.Report(w)) to see exactly which fields failed to bind.","Change the field to unexported if it should not be injected, or remove it if unused.","Fill the field with a non-zero value before registration (non-zero field values are picked up directly by lookupNonZeroFieldValues).","Disable MarkExportedFieldsAsRequired if strict field injection is not actually needed."],"exampleFix":"// before\ntype Ctx struct { DB *DB; Logger *Logger } // Logger has no dependency\ncontainer.MarkExportedFieldsAsRequired()\n// after\ncontainer.Register(func() *Logger { return log.New(os.Stdout, \"\", 0) })","handlingStrategy":"validation","validationCode":"// before enabling strict mode, verify each exported field type has a dependency\nfunc checkExportedFieldsBound(v any, depTypes map[reflect.Type]bool) []reflect.Type {\n    var missing []reflect.Type\n    t := reflect.Indirect(reflect.TypeOf(v))\n    for i := 0; i < t.NumField(); i++ {\n        f := t.Field(i)\n        if f.IsExported() && !depTypes[f.Type] {\n            missing = append(missing, f.Type)\n        }\n    }\n    return missing\n}","typeGuard":"func allExportedFieldsBindable(v any, depTypes map[reflect.Type]bool) bool {\n    return len(checkExportedFieldsBound(v, depTypes)) == 0\n}","tryCatchPattern":"func safeStructWithRequired(v any) (ok bool) {\n    defer func() {\n        if r := recover(); r != nil {\n            if s, isStr := r.(string); isStr && strings.Contains(s, \"MarkExportedFieldsAsRequired\") {\n                log.Printf(\"required-field binding failed: %s\", s)\n            } else { panic(r) }\n        }\n    }()\n    container.Register(v)\n    return true\n}","preventionTips":["Run container.Report(os.Stdout) whenever enabling MarkExportedFieldsAsRequired.","Only enable strict required mode on structs whose every exported field is a registered dependency type.","Keep injected fields unexported if they are optional, so strict mode skips them.","Add a CI test constructing every strict-mode struct so new fields force a matching dependency registration."],"tags":["go","dependency-injection","panic","required-fields","struct-binding"],"backgroundTag":"required-field-not-bound","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}