apache/beam · error

unexpected aggregate

Error message

unexpected aggregate %v, only slices allowed

What it means

During typex.Substitute, an Aggregate type whose underlying Go type is not a slice cannot be reconstructed from its substituted components: only reflect.Slice types can be rebuilt with reflect.SliceOf. Any other aggregate kind triggers this error.

Solutions

  1. Convert the aggregate to a slice type (e.g. use []T instead of [N]T) in your Fn signature or FullType construction.
  2. If a map is intended, model it with typex.Container/map semantics rather than an Aggregate node.
  3. Avoid substituting types with free variables inside array aggregates — bind to a fully concrete type instead.
  4. Check the %v in the message for the offending aggregate type to confirm which declaration to change.

Example fix

// before
typex.New(reflect.ArrayOf(2, typex.T.Type())) // array aggregate

// after
typex.New(reflect.SliceOf(typex.T.Type())) // slice aggregate
Defensive patterns

Strategy: type-guard

Validate before calling

func substitutableAggregate(t typex.FullType) bool {
    return t.Class() != typex.Aggregate || typex.IsList(t.Type())
}

Type guard

func isSliceAggregate(t typex.FullType) bool {
    return t.Class() == typex.Aggregate && t.Type().Kind() == reflect.Slice
}

Try / catch

out, err := typex.Substitute(t, m)
if err != nil && strings.Contains(err.Error(), "only slices allowed") {
    return fmt.Errorf("use slice-based types for generic aggregates: %w", err)
}

Prevention

When it happens

Trigger: Substituting a FullType containing an Aggregate node whose t.Type() is an array, map, struct, or other non-slice composite, with variable components — e.g. an aggregate built from [2]T or map[string]T passed through Substitute.

Common situations: Users construct FullTypes with typex.New over array or map Go types containing type variables and then run Substitute; the Beam type system's substitution only supports slice-shaped aggregates, so pipelines using array-typed variables with generic coders hit this.

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

Appendix: source

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

func substitute(t FullType, m map[string]reflect.Type) (FullType, error) {
	switch t.Class() {
	case Universal:
		name := t.Type().Name()
		repl, ok := m[name]
		if !ok {
			return nil, errors.Errorf("substituting type %v: type not bound", name)
		}
		return New(repl), nil
	case Container:
		comp, err := substituteList(t.Components(), m)
		if err != nil {
			return nil, err
		}
		if IsList(t.Type()) {
			return New(reflect.SliceOf(comp[0].Type()), comp...), nil
		}
		return nil, errors.Errorf("unexpected aggregate %v, only slices allowed", t)
	case Composite:
		comp, err := substituteList(t.Components(), m)
		if err != nil {
			return nil, err
		}
		return New(t.Type(), comp...), nil

	default:
		return t, nil
	}
}

func substituteList(list []FullType, m map[string]reflect.Type) ([]FullType, error) {
	var ret []FullType
	for _, elm := range list {
		repl, err := substitute(elm, m)
		if err != nil {
			return nil, err

View on GitHub (pinned to 12126d8942)