semaphoreui/semaphore · error
unsupported kind
Error message
unsupported kind %v
What it means
setBasicType (services/project/backup_marshal.go:147) only supports Bool, String, Int*, Uint*, and Float* kinds. If the destination reflect.Value has any other kind (time.Time, custom struct kinds reached here, complex, interface, etc.), it returns "unsupported kind %v". Struct/slice/map kinds are handled earlier in unmarshalValueWithBackupTags, so reaching this default indicates an unhandled leaf type.
Solutions
- Check which struct field triggered it and either add a case for that reflect.Kind in setBasicType (e.g. special handling for time.Time via string parsing).
- Exclude the field from backup processing with a `backup:"-"` struct tag.
- Change the field to one of the supported basic types (bool, string, int/uint/float).
- Pre-process the data so the field is a struct/slice/map (handled by other code paths) rather than an unsupported leaf kind.
Example fix
// before
type Env struct {
CreatedAt time.Time `backup:"created"`
}
// after
type Env struct {
CreatedAt time.Time `backup:"-"` // excluded from backup unmarshal
} Defensive patterns
Strategy: fallback
Validate before calling
v := reflect.ValueOf(target).Elem().FieldByName("CreatedAt")
switch v.Kind() {
case reflect.Bool, reflect.String, reflect.Int, reflect.Float64:
// supported
default:
return fmt.Errorf("field kind %v unsupported by backup unmarshaler", v.Kind())
} Type guard
func kindSupported(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool, reflect.String, reflect.Int, reflect.Int64, reflect.Uint64, reflect.Float64:
return true
}
return false
} Try / catch
if err := project.Unmarshal(data, &target); err != nil {
if strings.Contains(err.Error(), "unsupported kind") {
return fmt.Errorf("backup unmarshaler does not handle this field type: %w", err)
}
return err
} Prevention
- Restrict backup-tagged fields to bool/string/integer/float types.
- Tag complex leaf types (time.Time, json.RawMessage) with backup:"-" or add explicit handling.
- Add a unit test unmarshaling every backup entity struct.
When it happens
Trigger: A backup-tagged field has a kind not covered by setBasicType's switch - e.g. a time.Time value stored directly as a non-struct handling path, a complex128 field, or a custom named type whose kind falls through. Also produced deliberately in Test_SetBasicType_InvalidType_ReturnsError.
Common situations: Adding a field of a new type (time.Time, json.RawMessage, custom scalar) to a backup entity struct without extending setBasicType; schema evolution adding fields the unmarshaler does not yet handle.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cannot set value
- expected array for slice, got %T
- expected object for map[string]interface
- expected object for map, got %T
- expected bool for field, got %T
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/cdc3d25ed23474b2.
Report an issue: GitHub.
Appendix: source
Thrown at services/project/backup_marshal.go:147
n, ok := toFloat64(data)
if !ok {
return fmt.Errorf("expected number for field, got %T", data)
}
v.SetInt(int64(n))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
n, ok := toFloat64(data)
if !ok {
return fmt.Errorf("expected number for field, got %T", data)
}
v.SetUint(uint64(n))
case reflect.Float32, reflect.Float64:
n, ok := toFloat64(data)
if !ok {
return fmt.Errorf("expected number for field, got %T", data)
}
v.SetFloat(n)
default:
return fmt.Errorf("unsupported kind %v", v.Kind())
}
return nil
}
func toFloat64(data any) (float64, bool) {
switch n := data.(type) {
case float64:
return n, true
case float32:
return float64(n), true
case int:
return float64(n), true
case int64:
return float64(n), true
case int32:
return float64(n), true
case int16:
return float64(n), trueView on GitHub (pinned to 1774ccb71a)