apache/beam · error

first main input parameter must be a value type

Error message

first main input parameter must be a value type

What it means

When validating a DoFn (AsDoFn -> validateMainInputs), Beam requires the first main input parameter of ProcessElement to be a plain value (FnValue). Iterators (Iter) or re-iterators (ReIter) cannot be the first main input because the framework must hand the element itself before any iterable view.

Source

Thrown at sdks/go/pkg/beam/core/graph/fn.go:680

		err = errors.SetTopLevelMsgf(err,
			"Method %v in DoFn %v is missing all inputs. A main input is required.",
			methodName, fn.Name())
		return err
	}
	if num < int(numMainIn) {
		err := errors.Errorf("%v method has too few main inputs", methodName)
		err = errors.SetTopLevelMsgf(err,
			"Method %v in DoFn %v does not have enough main inputs. "+
				"%v main inputs were expected, but only %v inputs were found.",
			methodName, fn.Name(), numMainIn, num)
		return err
	}

	// Check that the first input is not an Iter or ReIter (those aren't valid
	// as the first main input).
	first := method.Param[pos].Kind
	if first != funcx.FnValue {
		err := errors.New("first main input parameter must be a value type")
		err = errors.SetTopLevelMsgf(err,
			"Method %v of DoFns should always have the first input be a value type, "+
				"but it has an Iter or ReIter first in DoFn %v.",
			processElementName, fn.Name())
		return errors.WithContextf(err, "method %v", processElementName)
	}
	return nil
}

// validateEmits compares the emits found in a DoFn method signature with the emits found in
// the signature for ProcessElement, and performs validation that those match. This function
// should only be used to validate methods that are expected to have the same emit parameters as
// ProcessElement.
func validateEmits(processFnEmits []funcx.FnParam, method *funcx.Fn, methodName string) error {
	posMethodEmits, numMethodEmits, ok := method.Emits()
	numProcessEmits := len(processFnEmits)

	// Handle cases where method has no emits.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Reorder ProcessElement parameters so a value-typed element comes first; put Iter/ReIter parameters after it.
  2. If the intent is full-group iteration, use a value parameter of a slice/KV type instead of an Iter as the first input.
  3. For GBK results, accept the CoGBK result type properly (KV<K, Iter<V>>) rather than a bare Iter main input.
  4. Use a side input if the iterable is a side view rather than a main input.

Example fix

// before
func (fn *f) ProcessElement(it func(func(int) bool), k string) {}
// after
func (fn *f) ProcessElement(k string, it func(func(int) bool)) {}
Defensive patterns

Strategy: validation

Validate before calling

func firstMainInputIsValue(fn reflect.Type, skip int) bool {
    return fn.In(skip).Kind() != reflect.Ptr || reflect.TypeOf(typex.EventTime(0)) != fn.In(skip).Elem()
}

Prevention

When it happens

Trigger: Declaring ProcessElement with an iterator parameter before the element, e.g. `ProcessElement(iter func(func(int) bool), v string)` where both are main inputs, or restructuring signatures so an Iter/ReIter precedes the element value.

Common situations: DoFns adapted from group-by-key patterns where whole-group iteration was intended but written as the first main input; porting from other SDKs where element iteration order is flexible.

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