apache/beam · error
bind conflict for : !=
Error message
bind conflict for %v: %v != %v
What it means
While walking a type tree during typex.Bind, the same type-variable name maps to two different concrete reflect.Types. The walk detects the conflict and aborts, since one variable name cannot bind to inconsistent concrete types.
Solutions
- Unify the concrete types so the repeated variable binds to exactly one reflect.Type, or use distinct variables (T, U) in the model.
- Inspect the message: name is the variable, then the two conflicting concrete types; change whichever one is wrong in your Fn signature.
- If the inputs are genuinely different types, change your PTransform signature to use separate type parameters instead of reusing one.
- Call typex.Bind with the pair whose conflict the message flags to reproduce and confirm before editing larger code.
Example fix
// before — one variable bound to two types func (fn *dedupFn) ProcessElement(a T, b T) // pipeline gives a=string, b=int // after — distinct variables func (fn *dedupFn) ProcessElement(a T, b U)
Defensive patterns
Strategy: validation
Validate before calling
func bindsConsistently(models, types []typex.FullType) bool {
m, err := typex.Bind(models, types)
if err != nil {
return false
}
for _, v := range m { _ = v }
return true
} Type guard
// Ensure each variable name appears with one concrete type before Bind:
seen := map[string]reflect.Type{}
for name, rt := range candidateBindings {
if prev, ok := seen[name]; ok && prev != rt {
return false // would cause bind conflict
}
seen[name] = rt
} Try / catch
m, err := typex.Bind(models, types)
var conflict *errors.E
if err != nil && strings.Contains(err.Error(), "bind conflict") {
return fmt.Errorf("variable bound to two types; split into distinct type variables: %w", err)
} Prevention
- Never reuse the same type variable (typex.T) for two positions that can hold different concrete types.
- Use distinct variables T, U, V for each independent input/output type in a DoFn or CombineFn.
- Validate that multi-input transforms receive homogeneous types when a single variable covers them.
- Keep Fn signatures and pipeline wiring in sync via code review or generated type checks.
When it happens
Trigger: A single type variable (e.g. T) appears in multiple positions of the model, and Bind is given concrete types that resolve T to different reflect.Types — e.g. X<T> paired with []string and X<int> paired with []int in the same Bind call.
Common situations: Users write a generic DoFn with a repeated type variable but feed heterogeneous input (e.g. KV<A,B> where they reused T for both A and B); also occurs when a custom aggregation or coders inference passes mismatched inputs to a multi-input step.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- typex.Bind: is not assignable to
- AfterProcessingTime trigger set without a delay or…
- array len mismatch. decoding
- At least one subtrigger required for composite triggers.
- attempted to add namespace to missing coder id
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/16c57c940fa3bfd0.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/typex/fulltype.go:379
}
if err := walk(t, model, m); err != nil {
return nil, err
}
}
return m, nil
}
func walk(t, model FullType, m map[string]reflect.Type) error {
switch t.Class() {
case Universal:
// By checking that the model is assignable to t, we know that they are
// structurally compatible. We rely on the exact reflect.Type in the
// Aggregate case to pick the correct binding, i.e., we do not need to
// construct such a type.
name := t.Type().Name()
if current, ok := m[name]; ok && current != model.Type() {
return errors.Errorf("bind conflict for %v: %v != %v", name, current, model.Type())
}
m[name] = model.Type()
return nil
case Composite, Container:
for i, elm := range t.Components() {
if err := walk(elm, model.Components()[i], m); err != nil {
return err
}
}
return nil
default:
return nil
}
}
// Substitute returns types identical to the given types, but with all
// universals substituted. All free type variables must be present in the
// substitution.View on GitHub (pinned to 12126d8942)