apache/beam · error

bind conflict for %v: %v != %v

Error message

bind conflict for %v: %v != %v

What it means

During generic binding in Satisfy (helper 'bind'), each universal (generic) type parameter is mapped by name to a concrete reflect.Type. This error is returned when the same generic type name would need to bind to two different concrete types, which would make the substitution inconsistent.

Source

Thrown at sdks/go/pkg/beam/core/funcx/signature.go:174

	}
	if err := matchOpt(in[:off], sig.OptArgs, m); err != nil {
		return err
	}
	if err := matchReq(out[:len(sig.Return)], sig.Return); err != nil {
		return err
	}
	return matchOpt(out[len(sig.Return):], sig.OptReturn, m)
}

func bind(list, models []reflect.Type, m map[string]reflect.Type) error {
	for i, t := range models {
		if !typex.IsUniversal(list[i]) {
			continue
		}

		name := list[i].Name()
		if current, ok := m[name]; ok && current != t {
			return errors.Errorf("bind conflict for %v: %v != %v", name, current, t)
		}
		m[name] = t
	}
	return nil
}

func matchReq(list, models []reflect.Type) error {
	for i, t := range list {
		if typex.IsUniversal(t) {
			continue // ok: if this was bad, there would be a bind conflict
		}

		model := models[i]
		if t.Kind() == reflect.Interface && model.Implements(t) {
			continue
		}
		if model != t {
			return &TypeMismatchError{Got: t, Want: model}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Make the types consistent so every occurrence of a generic name binds to the same concrete type.
  2. If the types are genuinely different, use distinct generic type names in the Signature.
  3. Check the inputs/outputs being fed to the function; ensure upstream producers emit the declared type.

Example fix

// before
func process(kv KV<X, X>) ... // KV<int,string> input: X binds to both int and string -> conflict
// after
func process(kv KV<X, Y>) ... // use two distinct generics
Defensive patterns

Strategy: validation

Validate before calling

in, out := fnTypeParams(fn)
bindings := map[string]reflect.Type{}
for _, t := range append(in, out...) {
    if name := genericName(t); name != "" {
        if prev, ok := bindings[name]; ok && prev != t {
            return fmt.Errorf("generic %s bound to both %v and %v", name, prev, t)
        }
        bindings[name] = t
    }
}

Prevention

When it happens

Trigger: Calling Satisfy with a function where one named generic (e.g. X) appears in multiple parameter or return positions that have different concrete types, e.g. fn func(A, B) (int, error) where A and B both refer to generic X.

Common situations: DoFn methods that process input of one type but emit a mismatched output type while the signature declares them as the same generic; typos in type parameters causing two generics to share a name; passing mixed-type collections (e.g. KV<A,B>) where a single type was expected.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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