semaphoreui/semaphore · error
expected string for field, got %T
Error message
expected string for field, got %T
What it means
In setBasicType (services/project/backup_marshal.go:125), when the destination field kind is String, the incoming data must be a JSON string. Any other Go type (number, bool, object, null) yields "expected string for field, got %T". This guards reflect.SetString against invalid types.
Solutions
- Quote the value in the backup JSON so it is a proper string (e.g. 123 -> "123").
- Change the struct field to a numeric type if the data is legitimately a number.
- Pre-validate the backup file's field types against the expected schema before restoring.
- Re-export the backup using a version whose schema matches the importing code.
Example fix
// before (backup.json) "project_id": 5 // after (field is a string type) "project_id": "5"
Defensive patterns
Strategy: validation
Validate before calling
if v, ok := raw["name"]; ok {
if _, ok := v.(string); !ok { return fmt.Errorf("field name must be string, got %T", v) }
} Type guard
func isString(v any) bool { _, ok := v.(string); return ok } Try / catch
if err := project.Unmarshal(data, &target); err != nil {
if strings.Contains(err.Error(), "expected string for field") {
return fmt.Errorf("backup schema mismatch: %w", err)
}
return err
} Prevention
- Quote string values in backup JSON even when they look numeric.
- Validate field types before restore.
- Match exporter and importer schema versions.
When it happens
Trigger: unmarshalValueWithBackupTags maps a backup JSON value of non-string type onto a struct field whose kind is String - e.g. a number where a string is expected.
Common situations: Backup JSON where a string field (e.g. an ID stored as string) was serialized as a number; hand-edited backups; schema drift between the exporting and importing versions where a field changed type from number to string.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- expected bool for field, got %T
- expected number for field, got %T
- expected object for struct, got %T
- must be valid JSON
- key can not be empty
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/03aeb806ba7c7a57.
Report an issue: GitHub.
Appendix: source
Thrown at services/project/backup_marshal.go:125
return v.Interface(), nil
}
func setBasicType(data any, v reflect.Value) error {
if !v.CanSet() {
return fmt.Errorf("cannot set value")
}
switch v.Kind() {
case reflect.Bool:
b, ok := data.(bool)
if !ok {
return fmt.Errorf("expected bool for field, got %T", data)
}
v.SetBool(b)
case reflect.String:
s, ok := data.(string)
if !ok {
return fmt.Errorf("expected string for field, got %T", data)
}
v.SetString(s)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
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)View on GitHub (pinned to 1774ccb71a)