{"record":{"id":"d187e550c640988b","repo":"apache/beam","slug":"interface-type-v-must-have-methods","errorCode":null,"errorMessage":"interface type %v must have methods","messagePattern":"interface type (.+?) must have methods","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/coder/row_decoder.go","lineNumber":57,"sourceCode":"\n// Register accepts a provider to decode schema encoded values\n// of that type.\n//\n// When decoding values, decoder functions produced by this builder will\n// first check for exact type matches, then interfaces implemented by\n// the type in recency order of registration, and then finally the\n// default Beam Schema encoding behavior.\n//\n// TODO(BEAM-9615): Add final factory types. This interface is subject to change.\n// Currently f must be a function  func(reflect.Type) (func(io.Reader) (any, error), error)\nfunc (b *RowDecoderBuilder) Register(rt reflect.Type, f any) {\n\tfd, ok := f.(decoderProvider)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"%T isn't a supported decoder function type (passed with %v), currently expecting %T\", f, rt, (decoderProvider)(nil)))\n\t}\n\n\tif rt.Kind() == reflect.Interface && rt.NumMethod() == 0 {\n\t\tpanic(fmt.Sprintf(\"interface type %v must have methods\", rt))\n\t}\n\n\tif b.allFuncs == nil {\n\t\tb.allFuncs = make(map[reflect.Type]decoderProvider)\n\t}\n\tb.allFuncs[rt] = fd\n\tif rt.Kind() == reflect.Interface {\n\t\tb.ifaceFuncs = append(b.ifaceFuncs, rt)\n\t}\n}\n\n// Build constructs a Beam Schema coder for the given type, using any providers registered for\n// itself or it's fields.\nfunc (b *RowDecoderBuilder) Build(rt reflect.Type) (func(io.Reader) (any, error), error) {\n\tif err := rowTypeValidation(rt, true); err != nil {\n\t\treturn nil, err\n\t}\n\treturn b.decoderForType(rt)","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/coder/row_decoder.go#L39-L75","documentation":"RowDecoderBuilder.Register panics when rt is the empty interface type (interface{}) with no methods. An empty interface cannot be decoded because the SDK cannot determine a concrete representation or schema for it, so registering a decoder factory for it is rejected.","triggerScenarios":"Calling b.Register(reflect.TypeOf((*any)(nil)).Elem(), decoderFn) or otherwise passing reflect.TypeOf of an empty interface type while registering row decoders.","commonSituations":"Generic helper code that stores the element type as any/interface{} and passes it through to Register without narrowing to the concrete element type.","solutions":["Pass the concrete struct type instead of interface{} (e.g. reflect.TypeOf(Foo{}))","In generic code, capture the concrete type via a typed parameter or type switch before calling Register"],"exampleFix":"// before\nb.Register(reflect.TypeOf((*any)(nil)).Elem(), decFn)\n// after\nb.Register(reflect.TypeOf(Foo{}), decFn)","handlingStrategy":"validation","validationCode":"if rt.Kind() == reflect.Interface && rt.NumMethod() == 0 {\n\treturn fmt.Errorf(\"cannot register decoder for empty interface %v\", rt)\n}","typeGuard":"func isRegisterableType(rt reflect.Type) bool {\n\treturn rt != nil && !(rt.Kind() == reflect.Interface && rt.NumMethod() == 0)\n}","tryCatchPattern":"func safeRegister(b *rowcoder.RowDecoderBuilder, rt reflect.Type, f any) (err error) {\n\tdefer func() { if r := recover(); r != nil { err = fmt.Errorf(\"register: %v\", r) } }()\n\tb.Register(rt, f)\n\treturn nil\n}","preventionTips":["Never register decoders against interface{}; use concrete struct types","In generic helpers, resolve the concrete type before calling Register"],"tags":["go","beam","reflection","interface"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}