kataras/iris · error

MarkExportedFieldsAsRequired is true and at least one of str

Error message

MarkExportedFieldsAsRequired is true and at least one of struct's (%s) field was not binded to a dependency.
Fields length: %d, matched exported bindings length: %d.
Use the Reporter for further details

What it means

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.

Source

Thrown at hero/binding.go:335

		})
	}

	inputs := make([]reflect.Type, n)
	for i := 0; i < n; i++ {
		// fmt.Printf("Controller [%s] | Field Index: %v | Field Type: %s\n", typ, fields[i].Index, fields[i].Type)
		inputs[i] = fields[i].Type
	}

	exportedBindings := getBindingsFor(inputs, dependencies, disablePayloadAutoBinding, paramsCount)

	// fmt.Printf("Controller [%s] | Inputs length: %d vs Bindings length: %d | NonZero: %d | Stateless : %d\n",
	// 	typ, n, len(exportedBindings), len(nonZero), stateless)
	// for i, b := range exportedBindings {
	// 	fmt.Printf("[%d] [Static=%v] %#+v\n", i, b.Dependency.Static, b.Dependency.OriginalValue)
	// }

	if markExportedFieldsAsRequired && len(exportedBindings) != n {
		panic(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)))
	}

	if stateless == 0 && len(nonZero) >= len(exportedBindings) {
		// if we have not a single stateless and fields are defined then just return.
		// Note(@kataras): this can accept further improvements.
		return
	}

	// get declared bindings from deps.
	bindings = append(bindings, exportedBindings...)
	for _, binding := range bindings {
		// fmt.Printf(""Controller [%s] | Binding: %s\n", typ, binding.String())

		if len(binding.Input.StructFieldIndex) == 0 {
			// set correctly the input's field index and name.
			f := fields[binding.Input.Index]
			binding.Input.StructFieldIndex = f.Index
			binding.Input.StructFieldName = f.Name

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Register a dependency for every missing exported field type, e.g. container.Register(func() *DB { return db }).
  2. Read the hero Reporter output (container.Report(w)) to see exactly which fields failed to bind.
  3. Change the field to unexported if it should not be injected, or remove it if unused.
  4. Fill the field with a non-zero value before registration (non-zero field values are picked up directly by lookupNonZeroFieldValues).
  5. Disable MarkExportedFieldsAsRequired if strict field injection is not actually needed.

Example fix

// before
type Ctx struct { DB *DB; Logger *Logger } // Logger has no dependency
container.MarkExportedFieldsAsRequired()
// after
container.Register(func() *Logger { return log.New(os.Stdout, "", 0) })
Defensive patterns

Strategy: validation

Validate before calling

// before enabling strict mode, verify each exported field type has a dependency
func checkExportedFieldsBound(v any, depTypes map[reflect.Type]bool) []reflect.Type {
    var missing []reflect.Type
    t := reflect.Indirect(reflect.TypeOf(v))
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        if f.IsExported() && !depTypes[f.Type] {
            missing = append(missing, f.Type)
        }
    }
    return missing
}

Type guard

func allExportedFieldsBindable(v any, depTypes map[reflect.Type]bool) bool {
    return len(checkExportedFieldsBound(v, depTypes)) == 0
}

Try / catch

func safeStructWithRequired(v any) (ok bool) {
    defer func() {
        if r := recover(); r != nil {
            if s, isStr := r.(string); isStr && strings.Contains(s, "MarkExportedFieldsAsRequired") {
                log.Printf("required-field binding failed: %s", s)
            } else { panic(r) }
        }
    }()
    container.Register(v)
    return true
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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