apache/beam · error

inferCoder failed: interface type %v has no coder registered

Error message

inferCoder failed: interface type %v has no coder registered

What it means

inferCoder tries to automatically pick a serialization coder for a Go type used in a PCollection. When it meets a reflect.Interface kind that does NOT implement JSON marshalling (json.Marshaler / encoding.TextMarshaler via jsonCoderType), no default coder exists and inference fails. The library refuses to guess a coder, so the user must register one explicitly.

Source

Thrown at sdks/go/pkg/beam/coder.go:241

				return coder.CoderFrom(c), nil
			}

			if EnableSchemas {
				switch et.Kind() {
				case reflect.Ptr:
					if et.Elem().Kind() != reflect.Struct {
						break
					}
					fallthrough
				case reflect.Struct:
					return &coder.Coder{Kind: coder.Row, T: t}, nil
				}
			}

			// Interface types that implement JSON marshalling can be handled by the default coder.
			// otherwise, inference needs to fail here.
			if et.Kind() == reflect.Interface && !et.Implements(jsonCoderType) {
				return nil, errors.Errorf("inferCoder failed: interface type %v has no coder registered", et)
			}

			c, err := newJSONCoder(et)
			if err != nil {
				return nil, err
			}
			return &coder.Coder{Kind: coder.Custom, T: t, Custom: c}, nil
		}

	case typex.Composite:
		c, err := inferCoders(t.Components())
		if err != nil {
			return nil, err
		}

		switch t.Type() {
		case typex.KVType:
			return &coder.Coder{Kind: coder.KV, T: t, Components: c}, nil

View on GitHub (pinned to 12126d8942)

Solutions

  1. Make the PCollection element a concrete type (struct or named concrete type) instead of an interface type.
  2. Implement json.Marshaler (and json.Unmarshaler) on the interface's concrete types so the default JSON coder can handle it.
  3. Register an explicit coder via beam.NewCoder / coder.NewCustomCoder for the type and pass it to the transform (e.g. beam.ParDo(..., beam.TypeDefinition{}, col) with coder, or combine.TryCombinePerKey with an explicit accum coder).
  4. Check the type at the failing call site: print reflect.TypeOf(value).Kind(); if it is reflect.Interface, restructure to a concrete element type.

Example fix

// before
beam.ParDo(s, &MyFn{}, col) // element type is interface{}

// after
type MyElem struct { Value string }
beam.ParDo(s, &MyFn{}, beam.ParDo(s, &ConcretizeFn{}, col), beam.TypeDefinition{Var: typex.NewVariable(0), T: reflect.TypeOf(MyElem{})})
// or implement MarshalJSON/UnmarshalJSON on the concrete types
Defensive patterns

Strategy: validation

Validate before calling

func canInferCoder(t reflect.Type) error {
  if t.Kind() == reflect.Interface && !t.Implements(jsonCoderType) {
    return fmt.Errorf("interface %v needs an explicit coder; use a concrete type or register one", t)
  }
  return nil
}

Type guard

func isCoderable(t reflect.Type) bool {
  return t != nil && (t.Kind() != reflect.Interface || t.Implements(jsonCoderType))
}

Prevention

When it happens

Trigger: Passing a pipeline element whose static type is an interface (e.g. interface{}, a user-defined interface, or a typed nil-carrier) to NewCoder/NewElementEncoder/NewElementDecoder, inferCoders, or a Combine (TryCombinePerKey), when the concrete dynamic type's interface does not implement json.Marshaler/TextMarshaler.

Common situations: Using []interface{} or map[string]interface{} as a PCollection element; defining DoFn process elements as a custom interface type; upgrading Beam Go where a previously unexported type became an interface in a signature; par-do chains that pass values through generic interfaces.

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


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/0ba7939a2f3997ea. Report an issue: GitHub.