apache/beam · error

unable to decode type

Error message

unable to decode type: %v

What it means

The RowDecoderBuilder encountered a Go type it cannot build a reflective decoder for (a kind not covered by its switch, e.g. unsupported container, channel, func, interface). Beam row coding only supports schema-encodable types.

Solutions

  1. Change the element type to only use supported kinds (primitives, strings, []byte, slices, maps, arrays, structs)
  2. Register a custom coder or implement schema/row encoding manually for the type
  3. Remove or convert the offending field before it enters the PCollection

Example fix

// before
type Event struct { Callback func(int) }
// after
type Event struct { CallbackID string }
Defensive patterns

Strategy: validation

Validate before calling

func decodable(t reflect.Type) bool {
    switch t.Kind() {
    case reflect.Chan, reflect.Func, reflect.Interface, reflect.UnsafePointer:
        return false
    }
    return true
}

Type guard

func isRowDecodable(v any) bool { return decodable(reflect.TypeOf(v)) }

Try / catch

if _, err := (coder.RowDecoderBuilder{}).Build(t); err != nil {
    return fmt.Errorf("type %T not row-decodable: %w", v, err)
}

Prevention

When it happens

Trigger: Calling beam encoding/decoding (DecoderForSlice, struct decoding, containerDecoderForType) on a type like chan, func, interface, or a nested unsupported element type reached recursively from a struct field.

Common situations: Users put unsupported field types (e.g. a chan or func) in a PCollection element struct and rely on default reflective row coding.

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

Appendix: source

Thrown at sdks/go/pkg/beam/core/graph/coder/row_decoder.go:391

		return typeDecoderFieldReflect{decode: iterableDecoderForSlice(t, decf)}, nil
	case reflect.Array:
		decf, err := b.containerDecoderForType(t.Elem())
		if err != nil {
			return typeDecoderFieldReflect{}, err
		}
		return typeDecoderFieldReflect{decode: iterableDecoderForArray(t, decf)}, nil
	case reflect.Map:
		decK, err := b.containerDecoderForType(t.Key())
		if err != nil {
			return typeDecoderFieldReflect{}, err
		}
		decV, err := b.containerDecoderForType(t.Elem())
		if err != nil {
			return typeDecoderFieldReflect{}, err
		}
		return typeDecoderFieldReflect{decode: mapDecoder(t, decK, decV)}, nil
	}
	return typeDecoderFieldReflect{}, errors.Errorf("unable to decode type: %v", t)
}

func (b *RowDecoderBuilder) containerDecoderForType(t reflect.Type) (typeDecoderFieldReflect, error) {
	dec, err := b.decoderForSingleTypeReflect(t)
	if err != nil {
		return typeDecoderFieldReflect{}, err
	}
	if t.Kind() == reflect.Ptr {
		return typeDecoderFieldReflect{decode: NullableDecoder(dec.decode), addr: dec.addr}, nil
	}
	return dec, nil
}

type typeDecoderReflect struct {
	typ    reflect.Type
	fields []typeDecoderFieldReflect
}

View on GitHub (pinned to 12126d8942)