OpenNHP/opennhp · error
unsupported field type
Error message
unsupported field type: %v in slice
What it means
Inside marshal, a slice-typed field is only supported if its element kind is Uint8 (encoded as raw bytes) or, via the preceding branch, an array/struct of supported element types. Any other slice element kind (e.g. []int32, []string, [][]byte) has no defined wire encoding in this format, so the serializer rejects it with this error.
Solutions
- Change the field to []byte and encode the data yourself (e.g. with encoding/binary or json.Marshal before storing).
- Replace []T (struct T) with a struct containing fixed-size fields, or encode each element into a byte slice.
- Keep slices out of ztdo structs; store variable-length data in the metadata section instead.
- Pre-encode the collection into a single []byte field before calling marshal/toBuffer.
Example fix
// before
type H struct {
Tags []string // unsupported
}
// after
type H struct {
TagsBytes []byte // json.Marshal(tags) beforehand
} Defensive patterns
Strategy: type-guard
Validate before calling
func sliceOK(t reflect.Type) bool {
if t.Kind() != reflect.Slice { return true }
return t.Elem().Kind() == reflect.Uint8 || t.Elem().Kind() == reflect.Struct
} Type guard
// fail fast at init
t := reflect.TypeOf(MyHeader{})
for i := 0; i < t.NumField(); i++ {
if ft := t.Field(i).Type; ft.Kind() == reflect.Slice && ft.Elem().Kind() != reflect.Uint8 {
panic("ztdo field " + t.Field(i).Name + " must be []byte")
}
} Try / catch
if err := marshal(buf, s); err != nil {
if strings.Contains(err.Error(), "unsupported field type") {
return fmt.Errorf("field in %T has no ztdo encoding: pre-encode to []byte", s)
}
return err
} Prevention
- Use []byte for any variable-length data in ztdo structs
- Pre-encode collections (json/binary) into a byte field
- Review struct fields against marshal's supported kinds when adding fields
When it happens
Trigger: Marshaling a struct containing a slice field whose element type is not uint8 and not handled by the struct/array branch — e.g. []int, []string, []float64, or a slice of structs containing unsupported nested types.
Common situations: Adding a convenience field like Tags []string or Scores []float64 to a ztdo header/metadata struct; refactoring a fixed-size array field into a slice; reusing a JSON-oriented struct directly for ztdo serialization.
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
- unsupported field type
- data must be a struct
- unsupported element type
- failed to marshal evidence
- data must be a pointer
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/6447748b7a82d47a.
Report an issue: GitHub.
Appendix: source
Thrown at nhp/core/ztdo/ztdo.go:515
if err := marshal(buf, field.Interface()); err != nil {
return err
}
} else {
var bytes []byte
if field.Type().Kind() == reflect.Array { // here assume it's an array of byte.
bytes = make([]byte, field.Len())
reflect.Copy(reflect.ValueOf(bytes), field)
} else if field.Type().Kind() == reflect.Slice {
if field.Type().Elem().Kind() == reflect.Struct {
for j := range field.Len() {
if err := marshal(buf, field.Index(j).Interface()); err != nil {
return err
}
}
} else if field.Type().Elem().Kind() == reflect.Uint8 {
bytes = field.Interface().([]byte)
} else {
return fmt.Errorf("unsupported field type: %v in slice", field.Type().Elem().Kind())
}
} else {
return fmt.Errorf("unsupported field type: %v", field.Type().Kind())
}
if _, err := buf.Write(bytes); err != nil {
return err
}
}
}
return nil
}
// unmarshal recursively deserializes binary data from a file into a Go struct
func unmarshal(f *os.File, data any) error {
rValues := reflect.ValueOf(data)
rTypes := reflect.TypeOf(data)View on GitHub (pinned to 6e04ca5ff0)