apache/beam · error

Unexpected aggregate type: %v

Error message

Unexpected aggregate type: %v

What it means

FullType.New builds the typed tree for pipeline data types and panics when an Aggregate-class reflect.Type is neither an array, slice, nor other handled aggregate kind. It means New was handed a type classified as Container/aggregate whose Go kind is not one it can decompose into element components.

Source

Thrown at sdks/go/pkg/beam/core/typex/fulltype.go:121

func New(t reflect.Type, components ...FullType) FullType {
	checkTypesNotNil(components)

	class := ClassOf(t)
	switch class {
	case Concrete, Universal:
		return &tree{class, t, nil}
	case Container:
		switch t.Kind() {
		case reflect.Slice:
			if len(components) == 0 {
				// For elements without sub components, we just create with the type, this handles vanilla slices.
				// We include the child type as a component for convenience.
				return &tree{class, t, []FullType{New(t.Elem())}}
			}
			// For elements which themselves have components, we need to go deeper.
			return &tree{class, t, []FullType{New(t.Elem(), components[0].Components()...)}}
		default:
			panic(fmt.Sprintf("Unexpected aggregate type: %v", t))
		}
	case Composite:
		switch t {
		case KVType:
			if len(components) != 2 {
				panic(fmt.Sprintf("Invalid number of components for KV: %v, %v", t, components))
			}
			if isAnyNonKVAndNonWindowedComposite(components) {
				panic(fmt.Sprintf("Invalid to nest composite composites inside KV: %v, %v", t, components))
			}
			return &tree{class, t, components}
		case WindowedValueType:
			if len(components) != 1 {
				panic("Invalid number of components for WindowedValue")
			}
			if components[0].Type() == WindowedValueType {
				panic("Invalid to nest WindowedValue")
			}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Let the SDK derive classes automatically; call typex.New(reflect.TypeOf(x)) without forcing a class.
  2. Use standard slice/array types for aggregations rather than custom kinds.
  3. Check that any custom class computation (e.g. Container) matches the actual reflect kind.

Example fix

// before
ft := typex.New(typex.Container, reflect.TypeOf(42)) // class/kind mismatch panics
// after
ft := typex.New(reflect.TypeOf([]int{}))
Defensive patterns

Strategy: validation

Validate before calling

if t.Kind() != reflect.Slice && t.Kind() != reflect.Array {
	return fmt.Errorf("expected aggregate slice/array type, got %v", t.Kind())
}

Type guard

func isSliceOrArray(t reflect.Type) bool {
	return t.Kind() == reflect.Slice || t.Kind() == reflect.Array
}

Prevention

When it happens

Trigger: Calling typex.New (directly or via GroupByKey, CoGroupByKey, CombinePerKey, CombineGlobally, Flatten, Prefix) with an aggregate-classed type whose reflect kind is not slice/array/map-chan-handled, e.g. via an incorrect class parameter or exotic types.

Common situations: Hand-constructing FullType trees with mismatched class/kind pairs; custom graph builders classifying types incorrectly before calling New; SDK bugs with unusual reflect kinds.

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


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