apache/beam · error
bad pair: %+v
Error message
bad pair: %+v
What it means
DecodeCoderRef converts an encoded CoderRef back into a usable coder. A pair-type ref must have exactly two components (key and value); any other count means the encoded form is corrupt or was produced by an incompatible encoder, so decoding fails with the full ref in the message.
Solutions
- Inspect the printed CoderRef and confirm the pipeline graph source; regenerate it from the original pipeline rather than reusing a stale artifact.
- Ensure the SDK version decoding the pipeline matches the version that encoded it.
- If using custom graph-rewriting tools, verify they preserve pair-coder component count.
- Re-export/rebuild the pipeline so the coder graph is re-encoded from valid in-memory coders.
Example fix
// before (corrupt ref)
ref := &graphx.CoderRef{Type: graphx.Pair, Components: []*graphx.CoderRef{key}}
c, err := graphx.DecodeCoderRef(ref)
// after
ref := &graphx.CoderRef{Type: graphx.Pair, Components: []*graphx.CoderRef{key, value}}
c, err := graphx.DecodeCoderRef(ref) Defensive patterns
Strategy: try-catch
Validate before calling
func validPairRef(r *graphx.CoderRef) bool {
return r != nil && r.Type == graphx.Pair && len(r.Components) == 2
} Type guard
func isPairRef(r *graphx.CoderRef) bool { return r != nil && r.Type == graphx.Pair && len(r.Components) == 2 } Try / catch
c, err := graphx.DecodeCoderRef(ref)
if err != nil {
if strings.Contains(err.Error(), "bad pair") {
return nil, fmt.Errorf("corrupt pair coder ref %v: regenerate the pipeline artifact: %w", ref, err)
}
return nil, err
} Prevention
- Never hand-edit encoded pipeline graphs
- Validate decoded graphs against the same SDK version that encoded them
- Checksum pipeline artifacts in CI before reuse
When it happens
Trigger: Decoding a CoderRef with Type pairType whose Components slice has length != 2 — e.g. during pipeline deserialization of a model/Job message whose coder graph was corrupted, truncated, or produced by a different Beam version.
Common situations: Loading a pipeline artifact or model-pipeline.proto edited by hand; cross-version decode (SDK encodes pair differently then another version decodes); corrupted service responses for the Dataflow pipeline graph; custom tooling that rewrites CoderRef components.
Related errors
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/294462911b2117ad.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/dataflow.go:252
switch c.Type {
case bytesType:
return coder.NewBytes(), nil
case boolType:
return coder.NewBool(), nil
case varIntType:
return coder.NewVarInt(), nil
case doubleType:
return coder.NewDouble(), nil
case stringType:
return coder.NewString(), nil
case pairType:
if len(c.Components) != 2 {
return nil, errors.Errorf("bad pair: %+v", c)
}
key, err := DecodeCoderRef(c.Components[0])
if err != nil {
return nil, err
}
elm := c.Components[1]
if elm.Type == streamType {
// TODO(https://github.com/apache/beam/issues/18032): If CoGBK with > 1 input, handle as special GBK. We expect
// it to be encoded as CoGBK<K,LP<Union<V,W,..>>. Remove this handling once
// CoGBK has a first-class representation.
if refs, ok := isCoGBKList(elm.Components[0]); ok {
values, err := DecodeCoderRefs(refs)
if err != nil {
return nil, err
}View on GitHub (pinned to 12126d8942)