apache/beam · error

can't generate row coder for type

Error message

can't generate row coder for type %v: must be a struct type or pointer to a struct type

What it means

rowTypeValidation rejects any reflect.Type whose kind is neither Struct nor Ptr when building a Beam row coder, erroring with "can't generate row coder for type %v: must be a struct type or pointer to a struct type". Beam's row encoding only supports (pointers to) structs; maps, slices, primitives, and interfaces cannot be encoded as rows.

Solutions

  1. Wrap the value in a struct type before row-coding it
  2. Use a pointer to the struct if needed (both Struct and Ptr kinds are accepted)
  3. Use a different coder (e.g. a custom coder via RegisterCoder) for non-struct types

Example fix

// before
b.Build(reflect.TypeOf("")) // string: unsupported
// after
type Payload struct { Value string }
b.Build(reflect.TypeOf(Payload{}))
Defensive patterns

Strategy: validation

Validate before calling

func rowCodable(t reflect.Type) bool {
    k := t.Kind()
    return k == reflect.Struct || k == reflect.Ptr
}

Type guard

func isStructOrPtr(t reflect.Type) bool { k := t.Kind(); return k == reflect.Struct || k == reflect.Ptr }

Try / catch

if err != nil && strings.Contains(err.Error(), "must be a struct type") {
    return fmt.Errorf("row coder requires a struct: %w", err)
}

Prevention

When it happens

Trigger: Calling RowEncoderBuilder.Build() with a type like int, string, []T, map[K]V, or an interface type, which reaches rowTypeValidation and fails the kind switch.

Common situations: Passing a named primitive type (e.g. type UserId string) to the row coder builder; wiring a schema/row coder to a slice element in a DoFn; schema registry misconfiguration.

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/b645ef0644aa99e7. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/core/graph/coder/row.go:70

// schema row.
func RowEncoderForStruct(rt reflect.Type) (func(any, io.Writer) error, error) {
	return defaultEnc.Build(rt)
}

// RowDecoderForStruct returns a decoding function that decodes the beam row encoding
// into the given type.
//
// Returns an error if the given type is invalid or not decodable from a beam
// schema row.
func RowDecoderForStruct(rt reflect.Type) (func(io.Reader) (any, error), error) {
	return defaultDec.Build(rt)
}

func rowTypeValidation(rt reflect.Type, strictExportedFields bool) error {
	switch k := rt.Kind(); k {
	case reflect.Ptr, reflect.Struct:
	default:
		return errors.Errorf("can't generate row coder for type %v: must be a struct type or pointer to a struct type", rt)
	}
	// TODO exported field validation.
	return nil
}

// writeRowHeader handles the field header for row encodings.
func writeRowHeader(rv reflect.Value, w io.Writer) error {
	// Row/Structs are prefixed with the number of fields that are encoded in total.
	if err := EncodeVarInt(int64(rv.NumField()), w); err != nil {
		return err
	}
	// Followed by a packed bit array of the nil fields.
	var curByte byte
	var nils bool
	var bytes = make([]byte, 0, rv.NumField()/8+1)
	for i := 0; i < rv.NumField(); i++ {
		shift := i % 8
		if i != 0 && shift == 0 {

View on GitHub (pinned to 12126d8942)