kubernetes/kops · error
BuildFlagsList of value type not handled: %T %s=%v
Error message
BuildFlagsList of value type not handled: %T %s=%v
What it means
After maps and slices, the walker switches on scalar/value kinds it can render: string, *string, bool, ints, floats, metav1.Duration and resource.Quantity. A field with a `flag` tag of any other type (e.g. time.Time, custom struct, map-like value type) hits the default case and returns this error.
Source
Thrown at pkg/flagbuilder/build_flags.go:203
// Go renders a time.Duration to `0` in <= 1.6, and `0s` in >= 1.7
// We force it to be `0s`, regardless of value
if vString == "0" {
vString = "0s"
}
if vString != flagEmpty {
flag = fmt.Sprintf("--%s=%s", flagName, vString)
}
case resource.Quantity:
// Format as a floating point value (i.e. 3.14, not 3140m)
vString := v.AsDec().String()
if vString != flagEmpty {
flag = fmt.Sprintf("--%s=%s", flagName, vString)
}
default:
return fmt.Errorf("BuildFlagsList of value type not handled: %T %s=%v", v, path, v)
}
if flag != "" {
flags = append(flags, flag)
}
return reflectutils.SkipReflection
}
err := reflectutils.ReflectRecursive(reflect.ValueOf(options), walker, &reflectutils.ReflectOptions{DeprecatedDoubleVisit: true})
if err != nil {
return nil, fmt.Errorf("BuildFlagsList to reflect value: %s", err)
}
// Sort so that the order is stable across runs
sort.Strings(flags)
return flags, nil
}
// maybeQuote quotes s when it contains a double quote, so values survive the space-separatedView on GitHub (pinned to 4c8573c808)
Solutions
- Change the field to one of the supported types (string, *string, bool, int/int32/int64, float32/float64, metav1.Duration, resource.Quantity)
- Remove the `flag` tag so the field is skipped or descended instead of rendered
- Extend the switch at build_flags.go:146-203 to handle the new type
Example fix
// before IdleTimeout time.Duration `flag:"idle-timeout"` // after IdleTimeout metav1.Duration `flag:"idle-timeout"`
Defensive patterns
Strategy: validation
Validate before calling
// Check flag-tagged leaf fields use a supported type before building flags
supported := map[reflect.Type]bool{
reflect.TypeOf(""): true,
reflect.TypeOf((*string)(nil)): true,
reflect.TypeOf(false): true,
reflect.TypeOf(int32(0)): true,
reflect.TypeOf(int64(0)): true,
reflect.TypeOf(metav1.Duration{}): true,
reflect.TypeOf(resource.Quantity{}): true,
}
v := reflect.ValueOf(opts).FieldByName("IdleTimeout")
if !supported[v.Type()] {
return fmt.Errorf("field type %s not supported by flagbuilder", v.Type())
} Type guard
func isFlaggableScalar(v reflect.Value) bool {
switch v.Interface().(type) {
case string, *string, bool, int, int32, int64, float32, float64, metav1.Duration, resource.Quantity:
return true
}
return false
} Try / catch
flags, err := flagbuilder.BuildFlagsList(opts)
if err != nil {
if strings.Contains(err.Error(), "BuildFlagsList of value type not handled") {
log.Fatalf("flag-tagged field has unsupported type: %v", err)
}
return err
} Prevention
- Use metav1.Duration, not time.Duration, in flaggable structs
- Keep the flagbuilder type switch in mind when adding new config fields
- Cover all option structs with BuildFlagsList tests
When it happens
Trigger: A field with a `flag` tag has a scalar type outside the supported switch, such as time.Time, time.Duration (bare, not metav1.Duration), int8/uint, or a nested struct value reached at leaf position.
Common situations: Using stdlib time.Duration instead of metav1.Duration in a flaggable config struct, adding a new typed field and forgetting the flag tag, or nesting structs that end up as leaves with a `flag` tag.
Related errors
- BuildFlags of value type not handled: %T %s=%v
- cannot parse flag spec: %q
- BuildFlagsList to reflect value: %s
- unhandled type %v %q
- unhandled type %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/3f033ffaccdca7a4.
Report an issue: GitHub.