{"record":{"id":"c1a8cad6f0768ab8","repo":"vitessio/vitess","slug":"no-default-getfunc-for-type-t-call-configure-wit","errorCode":null,"errorMessage":"no default GetFunc for type %T; call Configure with a custom GetFunc","messagePattern":"no default GetFunc for type %T; call Configure with a custom GetFunc","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/viperutil/get_func.go","lineNumber":181,"sourceCode":"\tcase reflect.Struct:\n\t\tswitch typ {\n\t\tcase reflect.TypeFor[time.Time]():\n\t\t\tf = func(v *viper.Viper) func(key string) time.Time {\n\t\t\t\treturn v.GetTime\n\t\t\t}\n\t\tdefault:\n\t\t\tf2 := unmarshalFunc[*T]()\n\t\t\tf = func(v *viper.Viper) func(key string) T {\n\t\t\t\tgetPointer := f2(v)\n\t\t\t\treturn func(key string) T {\n\t\t\t\t\treturn *getPointer(key)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif f == nil {\n\t\tpanic(fmt.Sprintf(\"no default GetFunc for type %T; call Configure with a custom GetFunc\", t))\n\t}\n\treturn f.(func(v *viper.Viper) func(key string) T)\n}\n\nfunc unmarshalFunc[T any]() func(v *viper.Viper) func(key string) T {\n\treturn func(v *viper.Viper) func(key string) T {\n\t\treturn func(key string) T {\n\t\t\tt := new(T)\n\t\t\t_ = v.UnmarshalKey(key, t) // TODO: panic on this error\n\t\t\treturn *t\n\t\t}\n\t}\n}\n\nfunc getCastedInt[T int8 | int16]() func(v *viper.Viper) func(key string) T {\n\treturn func(v *viper.Viper) func(key string) T {\n\t\treturn func(key string) T {\n\t\t\treturn T(v.GetInt(key))","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/viperutil/get_func.go#L163-L199","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Call viperutil.Configure with an explicit GetFunc for the type (e.g. viper.GetString / v.GetDuration / UnmarshalKey based)","Use the dedicated typed helpers that already exist (e.g. viperutil.ConfigureAndGet[time.Duration] only if registered — otherwise supply GetFunc: v.GetDuration)","Register a package-level default for the type in get_func.go if it is broadly useful"],"exampleFix":"// before\nviperutil.Configure(\"timeout\", viperutil.Options[time.Duration]{}) // panics\n// after\nviperutil.Configure(\"timeout\", viperutil.Options[time.Duration]{ GetFunc: func(v *viper.Viper) func(string) time.Duration { return v.GetDuration } })","handlingStrategy":"validation","validationCode":"// Verify the type has a default before relying on zero-value Options\nvar zero T\nswitch any(zero).(type) {\ncase string, bool, int, int8, int16, int32, int64,\n    uint, uint8, uint16, uint32, uint64, float32, float64:\n    // ok, has default\ndefault:\n    // slices/maps and registered types only — provide GetFunc otherwise\n}\n","typeGuard":"func hasDefaultGetFunc[T any]() bool {\n    _, ok := defaultGetFuncs[reflect.TypeOf(new(T)).Elem()]\n    return ok\n}","tryCatchPattern":"func configureSafe[T any](v *viper.Viper, key string, getFunc func(*viper.Viper) func(string) T) T {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Fatalf(\"viperutil: type %T needs an explicit GetFunc: %v\", *new(T), r)\n        }\n    }()\n    return viperutil.ConfigureAndGet[T](v, key)\n}","preventionTips":["Never rely on the zero value of viperutil.Options for non-primitive types — always set GetFunc unless the type is a known default","Check the registry/default kind switch in get_func.go before adding a new option type","Add a startup smoke test that configures every option so the panic surfaces in CI, not production"],"tags":["go","viper","config","generics","panic"],"backgroundTag":"unsupported-config-type","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}