apache/beam · error
interface type must have methods
Error message
interface type %v must have methods
What it means
RowEncoderBuilder.Register panics when rt is the empty interface (interface{}) with no methods. An empty interface has no schema or concrete representation, so the SDK cannot attach a custom row encoder to it and rejects the registration.
Solutions
- Register the concrete struct type (e.g. reflect.TypeOf(Foo{})) instead of interface{}
- Resolve the concrete type with a type switch or typed generic parameter before calling Register
Example fix
// before
b.Register(reflect.TypeOf((*any)(nil)).Elem(), encFn)
// after
b.Register(reflect.TypeOf(Foo{}), encFn) Defensive patterns
Strategy: validation
Validate before calling
if rt.Kind() == reflect.Interface && rt.NumMethod() == 0 {
return fmt.Errorf("cannot register encoder for empty interface %v", rt)
} Type guard
func isRegisterableType(rt reflect.Type) bool {
return rt != nil && !(rt.Kind() == reflect.Interface && rt.NumMethod() == 0)
} Try / catch
func safeRegister(b *rowcoder.RowEncoderBuilder, rt reflect.Type, f any) (err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("register: %v", r) } }()
b.Register(rt, f)
return nil
} Prevention
- Register concrete types only; never interface{}
- Resolve generic/any element types with a type switch before Register
When it happens
Trigger: Calling b.Register(reflect.TypeOf((*any)(nil)).Elem(), encFn) or passing any zero-method interface type as rt while registering row encoders.
Common situations: Generic pipeline helpers that thread element types as interface{} and pass them straight through to Register without resolving to the concrete type.
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
- interface type must have methods
- bad decode
- bad encode
- cannot make schema encoder for type
- cannot make schema encoder for type
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/181e8050adfb1a7a.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/graph/coder/row_encoder.go:55
type encoderProvider = func(reflect.Type) (func(any, io.Writer) error, error)
// Register accepts a provider for the given type to schema encode values of that type.
//
// When generating encoding functions, this builder will first check for exact type
// matches, then against interfaces with registered factories in recency order of
// registration, and then finally use the default Beam Schema encoding behavior.
//
// TODO(BEAM-9615): Add final factory types. This interface is subject to change.
// Currently f must be a function of the type func(reflect.Type) func(T, io.Writer) (error).
func (b *RowEncoderBuilder) Register(rt reflect.Type, f any) {
fe, ok := f.(encoderProvider)
if !ok {
panic(fmt.Sprintf("%T isn't a supported encoder function type (passed with %v)", f, rt))
}
if rt.Kind() == reflect.Interface && rt.NumMethod() == 0 {
panic(fmt.Sprintf("interface type %v must have methods", rt))
}
if b.allFuncs == nil {
b.allFuncs = make(map[reflect.Type]encoderProvider)
}
b.allFuncs[rt] = fe
if rt.Kind() == reflect.Interface {
b.ifaceFuncs = append(b.ifaceFuncs, rt)
}
}
// Build constructs a Beam Schema coder for the given type, using any providers registered for
// itself or it's fields.
func (b *RowEncoderBuilder) Build(rt reflect.Type) (func(any, io.Writer) error, error) {
if err := rowTypeValidation(rt, true); err != nil {
return nil, err
}
return b.encoderForType(rt)
}View on GitHub (pinned to 12126d8942)