apache/beam · error
bad I
Error message
bad I: %v
What it means
EncodeCoderRef serializes a coder into the runner (Dataflow) representation. A coder.Iterable must wrap exactly one component coder (the element coder); any other component count is structurally invalid, so encoding aborts with this error naming the coder. This prevents emitting a stream CoderRef the service cannot interpret.
Solutions
- Ensure the Iterable coder has exactly one component: len(c.Components) == 1.
- Create iterable coders through the SDK (e.g. coder.NewI, or coders inferred from typex.Stream types) rather than by hand.
- Inspect the PCollection whose coder triggers this and fix the custom coder override.
- Align SDK versions if the coder was produced by decode of an older/newer pipeline artifact.
Example fix
// before
c := &coder.Coder{Kind: coder.Iterable, T: t, Components: nil}
ref, err := graphx.EncodeCoderRef(c)
// after
elem := graphx.InferCoder(typex.New(typex.StringType))
c := &coder.Coder{Kind: coder.Iterable, T: typex.New(typex.StreamType, elem.T), Components: []*coder.Coder{elem}}
ref, err := graphx.EncodeCoderRef(c) Defensive patterns
Strategy: validation
Validate before calling
func validIterable(c *coder.Coder) bool {
return c != nil && c.Kind == coder.Iterable && len(c.Components) == 1
} Type guard
func hasComponents(c *coder.Coder, n int) bool { return c != nil && len(c.Components) == n } Try / catch
ref, err := graphx.EncodeCoderRef(c)
if err != nil {
if strings.Contains(err.Error(), "bad I") {
return fmt.Errorf("iterable coder must have exactly 1 element component: %w", err)
}
return err
} Prevention
- Use coder.NewI / type-inferred coders instead of hand-built structs
- Add a pre-submission validation pass over all PCollection coders
- Don't overwrite coders of intermediate PCollections in custom transforms
When it happens
Trigger: Encoding a coder.Coder with Kind coder.Iterable whose Components slice is empty or has more than one entry — typically via EncodeCoder/EncodeCoderRefs during pipeline submission to Dataflow.
Common situations: Manually constructed iterable coders with no element component; a GBK/PCollection transform whose output coder was overwritten with a wrong shape; version skew between the pipeline-graph serializer and a custom coder factory.
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/605307dc21835f8a.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/dataflow.go:135
value, err := EncodeCoderRef(c.Components[1])
if err != nil {
return nil, err
}
return &CoderRef{Type: pairType, Components: []*CoderRef{key, value}, IsPairLike: true}, nil
case coder.Nullable:
if len(c.Components) != 1 {
return nil, errors.Errorf("bad N: %v", c)
}
innerref, err := EncodeCoderRef(c.Components[0])
if err != nil {
return nil, err
}
return &CoderRef{Type: nullableType, Components: []*CoderRef{innerref}}, nil
case coder.Iterable:
if len(c.Components) != 1 {
return nil, errors.Errorf("bad I: %v", c)
}
innerref, err := EncodeCoderRef(c.Components[0])
if err != nil {
return nil, err
}
return &CoderRef{Type: streamType, Components: []*CoderRef{innerref}}, nil
case coder.CoGBK:
if len(c.Components) < 2 {
return nil, errors.Errorf("bad CoGBK: %v", c)
}
refs, err := EncodeCoderRefs(c.Components)
if err != nil {
return nil, err
}
value := refs[1]View on GitHub (pinned to 12126d8942)