kataras/iris · error

bad value: nil: %T

Error message

bad value: nil: %T

What it means

newDependency normalizes any user-supplied dependency (static value, struct, or resolving func) into a *Dependency. If the supplied value is nil (nil interface or typed-nil that valueOf turns into an invalid value), hero cannot represent it and panics immediately with 'bad value: nil'. This is a registration-time guard so bad dependency declarations fail at startup.

Source

Thrown at hero/dependency.go:90

	return fmt.Sprintf("%s (%#+v)", sourceLine, val)
}

// NewDependency converts a function or a function which accepts other dependencies or static struct value to a *Dependency.
//
// See `Container.Handler` for more.
func NewDependency(dependency any, funcDependencies ...*Dependency) *Dependency { // used only on tests.
	return newDependency(dependency, false, false, nil, funcDependencies...)
}

func newDependency(
	dependency any,
	disablePayloadAutoBinding bool,
	enableStructDependents bool,
	matchDependency DependencyMatcher,
	funcDependencies ...*Dependency,
) *Dependency {
	if dependency == nil {
		panic(fmt.Sprintf("bad value: nil: %T", dependency))
	}

	if d, ok := dependency.(*Dependency); ok {
		// already a *Dependency, do not continue (and most importatly do not call resolveDependency) .
		return d
	}

	v := valueOf(dependency)
	if !goodVal(v) {
		panic(fmt.Sprintf("bad value: %#+v", dependency))
	}

	if matchDependency == nil {
		matchDependency = DefaultDependencyMatcher
	}

	dest := &Dependency{
		Source:           newSource(v),

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Ensure the dependency value is initialized before registration: create the service instance (e.g. NewService()) rather than passing its nil pointer.
  2. Add a nil check before calling Register: if svc == nil { panic/log } then register.
  3. Return an error early from config loading instead of nil, so registration never sees nil.
  4. If the dependency is genuinely optional, do not register it; let hero resolve other bindings.
  5. Register a factory func (func() *Service) that builds the value lazily instead of a nil static value.

Example fix

// before
var svc *MyService
container.Register(svc) // panics: bad value: nil
// after
container.Register(func() *MyService { return NewMyService() })
Defensive patterns

Strategy: validation

Validate before calling

func mustRegister(c *hero.Container, dep any) {
    if dep == nil || reflect.ValueOf(dep).IsZero() {
        panic(fmt.Sprintf("refusing to register nil dependency %T", dep))
    }
    c.Register(dep)
}

Type guard

func isNonNil(v any) bool {
    if v == nil { return false }
    rv := reflect.ValueOf(v)
    switch rv.Kind() {
    case reflect.Ptr, reflect.Interface, reflect.Map, reflect.Slice, reflect.Func, reflect.Chan:
        return !rv.IsNil()
    default:
        return true
    }
}

Try / catch

func safeRegister(dep any) (ok bool) {
    defer func() {
        if r := recover(); r != nil {
            if s, isStr := r.(string); isStr && strings.Contains(s, "bad value") {
                log.Printf("dependency registration failed: %s", s)
            } else { panic(r) }
        }
    }()
    container.Register(dep)
    return true
}

Prevention

When it happens

Trigger: Calling Container.Register(nil), hero.NewDependency(nil), or NewDependency(nil) directly; registering a variable that is a nil *Dependency; a struct field whose value is a nil interface being fed into newDependency via getBindingsForStruct's nonZero field handling; passing a typed nil (e.g. (*Service)(nil)) that fails goodVal and surfaces the nil/bad-value path.

Common situations: A config/env loader returning nil before wiring dependencies; refactors where the dependency variable became a nil pointer; forgetting to initialize a service before container.Register(svc); map lookups returning a nil value passed straight to Register.

Related errors


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