apache/beam · error

too many return values: %v

Error message

too many return values: %v

What it means

findOutbound in bind.go converts a function's return values into the outbound type: 0 returns means no output, 1 becomes a plain type, 2 becomes a KV, and any other count is rejected. This error is returned when a DoFn process method returns 3 or more values, which the framework cannot represent.

Source

Thrown at sdks/go/pkg/beam/core/graph/bind.go:112

	return inbound, kinds, outbound, out, nil
}

func findOutbound(fn *funcx.Fn) ([]typex.FullType, error) {
	ret := trimIllegal(returnTypes(funcx.SubReturns(fn.Ret, fn.Returns(funcx.RetValue)...)))
	params := funcx.SubParams(fn.Param, fn.Params(funcx.FnEmit)...)

	var outbound []typex.FullType

	// The direct output is the "main" output, if any.
	switch len(ret) {
	case 0:
		break // ok: no direct output.
	case 1:
		outbound = append(outbound, typex.New(ret[0]))
	case 2:
		outbound = append(outbound, typex.NewKV(typex.New(ret[0]), typex.New(ret[1])))
	default:
		return nil, errors.Errorf("too many return values: %v", ret)
	}

	for _, param := range params {
		values, _ := funcx.UnfoldEmit(param.T)
		trimmed := trimIllegal(values)
		if len(trimmed) == 2 {
			outbound = append(outbound, typex.NewKV(typex.New(trimmed[0]), typex.New(trimmed[1])))
		} else {
			outbound = append(outbound, typex.New(trimmed[0]))
		}
	}
	return outbound, nil
}

func returnTypes(list []funcx.ReturnParam) []reflect.Type {
	var ret []reflect.Type
	for _, elm := range list {
		ret = append(ret, elm.T)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Reduce returns to at most two values (single type or KV) plus the allowed error/context forms.
  2. Use emit functions (func(X) emitter parameters) to produce multiple outputs instead of multiple return values.
  3. Pack multiple values into a struct or beam KV type and return that single value.

Example fix

// before
func (f *myFn) ProcessElement(ctx context.Context, s string) (int, string, error) { ... } // 3 returns
// after
func (f *myFn) ProcessElement(s string, emitStr func(string)) (int, error) { emitStr(s); return len(s), nil }
Defensive patterns

Strategy: validation

Validate before calling

if t := reflect.TypeOf(fn); t.NumOut() > 3 { // e.g. 2 values + error
    return fmt.Errorf("fn returns %d values; max supported is a single value or KV (plus error)", t.NumOut())
}

Prevention

When it happens

Trigger: Registering a DoFn whose ProcessElement returns 3+ values, e.g. (KV, T, error) or (A, B, C, error), via graph.Bind/newDoFnNode during pipeline construction.

Common situations: Wanting to emit multiple distinct outputs from one method - developers return them instead of using separate emitters; porting code that returns a tuple plus error; accidental extra return of a debug value.

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