apache/beam · warning
bad channel direction
Error message
bad channel direction
What it means
encodeType encodes channel types together with their direction via encodeChanDir; 'bad channel direction' means the channel's reflect.ChanDir could not be mapped to a protobuf ChanDir value. This is an internal mapping failure - the SDK's encodeChanDir only covers RecvDir, SendDir, and BothDir, so it should be unreachable for valid reflect types and signals an internal invariant violation or corrupted type metadata.
Solutions
- Report/verify against the Beam SDK version; upgrade to the latest patch release.
- Avoid channel types in serialized pipeline graphs entirely so this branch is never hit.
- Check whether a custom type wrapper is producing an invalid reflect.Type and fix it.
- File an issue with apache/beam including the wrapped error context ('encoding channel %v').
Defensive patterns
Strategy: try-catch
Try / catch
if _, err := graphx.EncodeFn(fn); err != nil && strings.Contains(err.Error(), "bad channel direction") {
return fmt.Errorf("likely Beam SDK bug; report with context: %w", err)
} Prevention
- Keep the Beam Go SDK up to date to pick up internal mapping fixes
- Avoid channel types in serialized pipeline graphs so this branch never executes
- Report occurrences to apache/beam with the full wrapped error chain
When it happens
Trigger: encodeType's reflect.Chan branch calls encodeChanDir with a direction outside the three valid reflect.ChanDir values - practically only via corrupted reflect metadata or an SDK-internal bug; triggered during pipeline graph export of a type containing a channel.
Common situations: Extremely rare; encountered when hacking reflect metadata, using unusual reflect constructs, or hitting a genuine Beam SDK bug while serializing channel-bearing types on remote runner export.
Related errors
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/304d519b51187ef6.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:494
for i := 0; i < t.NumOut(); i++ {
ret, err := encodeType(t.Out(i))
if err != nil {
wrapped := errors.Wrap(err, "bad return type")
return nil, errors.WithContextf(wrapped, "encoding function %v", t)
}
out = append(out, ret)
}
return &v1pb.Type{Kind: v1pb.Type_FUNC, ParameterTypes: in, ReturnTypes: out, IsVariadic: t.IsVariadic()}, nil
case reflect.Chan:
elm, err := encodeType(t.Elem())
if err != nil {
wrapped := errors.Wrap(err, "bad element type")
return nil, errors.WithContextf(wrapped, "encoding channel %v", t)
}
dir, err := encodeChanDir(t.ChanDir())
if err != nil {
wrapped := errors.Wrap(err, "bad channel direction")
return nil, errors.WithContextf(wrapped, "encoding channel %v", t)
}
return &v1pb.Type{Kind: v1pb.Type_CHAN, Element: elm, ChanDir: dir}, nil
case reflect.Ptr:
elm, err := encodeType(t.Elem())
if err != nil {
wrapped := errors.Wrap(err, "bad base type")
return nil, errors.WithContextf(wrapped, "encoding pointer %v", t)
}
return &v1pb.Type{Kind: v1pb.Type_PTR, Element: elm}, nil
case reflect.Map, reflect.Array:
return nil, errors.Errorf("unencodable type '%v', try to wrap the type as a field in a struct, see https://github.com/apache/beam/issues/23101 for details", t.Kind())
default:
return nil, errors.Errorf("unencodable type '%v'", t.Kind())
}View on GitHub (pinned to 12126d8942)