apache/beam · error
cannot convert to schema. FromType only converts structs to…
Error message
cannot convert %v to schema. FromType only converts structs to schemas
What it means
FromType only converts Go struct types into Beam Row schemas. If the passed reflect.Type (after skipping pointers) is not of Kind reflect.Struct, this error is returned directly. It signals API misuse: FromType is the wrong entry point for non-struct types.
Solutions
- Pass a struct type (or pointer to struct) to FromType.
- Wrap non-struct leaf types in a struct field or register a LogicalType via RegisterLogicalType.
- Assert before calling: reflectx.SkipPtr(t).Kind() == reflect.Struct.
Example fix
// before
t := reflect.TypeOf([]string{})
schm, err := reg.FromType(t) // error
// after
type Rows struct { Values []string }
schm, err := reg.FromType(reflect.TypeOf(Rows{})) Defensive patterns
Strategy: type-guard
Validate before calling
t := reflect.TypeOf(x)
if reflectx.SkipPtr(t).Kind() != reflect.Struct {
return nil, fmt.Errorf("%v is not a struct; FromType requires structs", t)
} Type guard
func isSchemaConvertibleStruct(v interface{}) bool {
return reflectx.SkipPtr(reflect.TypeOf(v)).Kind() == reflect.Struct
} Try / catch
schm, err := reg.FromType(t)
if err != nil && strings.Contains(err.Error(), "only converts structs") {
return nil, fmt.Errorf("wrap %v in a struct or register a logical type", t)
} Prevention
- Only pass struct types (or pointers to structs) to FromType.
- Wrap primitives/maps in a row struct before conversion.
- Guard with reflectx.SkipPtr(t).Kind() == reflect.Struct before calling.
- Use RegisterLogicalType for non-struct leaf types.
When it happens
Trigger: Calling Registry.FromType(reflect.TypeOf(x)) where x is a slice, map, string, int, or other non-struct (pointers are skipped, so the pointed-to kind is what matters).
Common situations: Trying to schema-encode a []byte, map, or primitive; accidentally passing reflect.TypeOf on a slice variable; converting wrapper types instead of their row structs.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- beam.RegisterSchemaProvider: unsupported type kind for…
- cannot convert field
- cannot make schema for type
- Logical Types may not be registered with empty interface…
- Logical Types must be registered with interface types.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/cec22f9f976fce18.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/schema/schema.go:325
// empty types have no value for lookups.
if synth != emptyStructType {
r.syntheticToUser[synth] = ut
r.syntheticToUser[reflect.PtrTo(synth)] = reflect.PtrTo(ut)
}
if ut != emptyStructType {
r.syntheticToUser[ut] = ut
r.syntheticToUser[reflect.PtrTo(ut)] = reflect.PtrTo(ut)
}
}
// FromType returns a Beam Schema of the passed in type.
// Returns an error if the type cannot be converted to a Schema.
func (r *Registry) FromType(ot reflect.Type) (*pipepb.Schema, error) {
if err := r.reconcileRegistrations(); err != nil {
return nil, errors.Wrap(err, "reconciling for FromType")
}
if reflectx.SkipPtr(ot).Kind() != reflect.Struct {
return nil, errors.Errorf("cannot convert %v to schema. FromType only converts structs to schemas", ot)
}
return r.fromType(ot)
}
func (r *Registry) logicalTypeToFieldType(t reflect.Type) (*pipepb.FieldType, string, error) {
// Check if a logical type was registered that matches this struct type directly
// and if so, extract the schema from it for use.
if lID, ok := r.logicalTypeIdentifiers[t]; ok {
lt := r.logicalTypes[lID]
ftype, err := r.reflectTypeToFieldType(lt.StorageType())
if err != nil {
return nil, "", errors.Wrapf(err, "unable to convert LogicalType[%v]'s storage type %v for Go type of %v to a schema", lID, lt.StorageType(), lt.GoType())
}
return ftype, lID, nil
}
for _, lti := range r.logicalTypeInterfaces {
if !t.Implements(lti) {
continueView on GitHub (pinned to 12126d8942)