vitessio/vitess · error

no default GetFunc for type %T; call Configure with a custom

Error message

no default GetFunc for type %T; call Configure with a custom GetFunc

What it means

After checking all supported reflect kinds, GetFuncForType[T] falls back to a registry of default GetFuncs keyed by type. If the concrete type T has no registered default (and Configure was not called with a custom GetFunc), it panics 'no default GetFunc for type %T'. This is the catch-all for types outside both the kind switch and the registry.

Source

Thrown at go/viperutil/get_func.go:181

	case reflect.Struct:
		switch typ {
		case reflect.TypeFor[time.Time]():
			f = func(v *viper.Viper) func(key string) time.Time {
				return v.GetTime
			}
		default:
			f2 := unmarshalFunc[*T]()
			f = func(v *viper.Viper) func(key string) T {
				getPointer := f2(v)
				return func(key string) T {
					return *getPointer(key)
				}
			}
		}
	}

	if f == nil {
		panic(fmt.Sprintf("no default GetFunc for type %T; call Configure with a custom GetFunc", t))
	}
	return f.(func(v *viper.Viper) func(key string) T)
}

func unmarshalFunc[T any]() func(v *viper.Viper) func(key string) T {
	return func(v *viper.Viper) func(key string) T {
		return func(key string) T {
			t := new(T)
			_ = v.UnmarshalKey(key, t) // TODO: panic on this error
			return *t
		}
	}
}

func getCastedInt[T int8 | int16]() func(v *viper.Viper) func(key string) T {
	return func(v *viper.Viper) func(key string) T {
		return func(key string) T {
			return T(v.GetInt(key))

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Call viperutil.Configure with an explicit GetFunc for the type (e.g. viper.GetString / v.GetDuration / UnmarshalKey based)
  2. Use the dedicated typed helpers that already exist (e.g. viperutil.ConfigureAndGet[time.Duration] only if registered — otherwise supply GetFunc: v.GetDuration)
  3. Register a package-level default for the type in get_func.go if it is broadly useful

Example fix

// before
viperutil.Configure("timeout", viperutil.Options[time.Duration]{}) // panics
// after
viperutil.Configure("timeout", viperutil.Options[time.Duration]{ GetFunc: func(v *viper.Viper) func(string) time.Duration { return v.GetDuration } })
Defensive patterns

Strategy: validation

Validate before calling

// Verify the type has a default before relying on zero-value Options
var zero T
switch any(zero).(type) {
case string, bool, int, int8, int16, int32, int64,
    uint, uint8, uint16, uint32, uint64, float32, float64:
    // ok, has default
default:
    // slices/maps and registered types only — provide GetFunc otherwise
}

Type guard

func hasDefaultGetFunc[T any]() bool {
    _, ok := defaultGetFuncs[reflect.TypeOf(new(T)).Elem()]
    return ok
}

Try / catch

func configureSafe[T any](v *viper.Viper, key string, getFunc func(*viper.Viper) func(string) T) T {
    defer func() {
        if r := recover(); r != nil {
            log.Fatalf("viperutil: type %T needs an explicit GetFunc: %v", *new(T), r)
        }
    }()
    return viperutil.ConfigureAndGet[T](v, key)
}

Prevention

When it happens

Trigger: Requesting a getter for a type like time.Duration, net.Addr, or a custom struct without registering a default GetFunc, and calling viperutil.Configure with GetFunc: nil (zero-value Options).

Common situations: A developer relies on the zero value of viperutil.Options (GetFunc nil) assuming their type has a built-in default; only a handful of types (string, bool, ints, floats, slices, string-keyed maps, registered specials) do.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/c1a8cad6f0768ab8. Report an issue: GitHub.