apache/beam · error
Expected single output PCollection in reshuffle:
Error message
Expected single output PCollection in reshuffle:
What it means
Symmetric to the input check: a Reshuffle transform must produce exactly one output PCollection so prism can elide it and reconnect consumers to the input collection. A multi-output reshuffle means the graph violates the runner's assumption and it panics with the transform dump.
Solutions
- Read the prototext dump to see the outputs attached to the reshuffle transform.
- Rebuild the pipeline with standard beam.Reshuffle() so the SDK emits exactly one output.
- Fix custom graph-rewriting code so reshuffle nodes keep exactly one output PCollection.
- Report upstream if a normal pipeline yields multi-output reshuffles.
Defensive patterns
Strategy: validation
Validate before calling
if isReshuffle(t) && len(t.GetOutputs()) != 1 { /* fix graph before submission */ } Try / catch
defer func(){ if r := recover(); r != nil && strings.Contains(fmt.Sprint(r), "Expected single output PCollection in reshuffle") { /* inspect transform dump */ } }() Prevention
- Never fan reshuffle output to multiple collections
- Regenerate graphs with the standard SDK APIs
When it happens
Trigger: handleReshuffle receives a PTransform whose outputs map has zero or multiple entries — e.g. a malformed or custom-built Reshuffle node, or post-processing that added outputs to the transform.
Common situations: Hand-built or tool-generated pipeline graphs; graph rewriters that fan reshuffle output to multiple collections before submission; corrupted or doctored job-submission requests.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Expected single input PCollection in reshuffle:
- SDK side reshuffle not yet supported
- expected CoGBK, got
- failed to expand Reshuffle transform for edge
- invalid pcollection
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/1f9b6b9b1b8c3dfd.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/runners/prism/internal/handlerunner.go:188
}
// A Reshuffle, in principle, is a no-op on the pipeline structure, WRT correctness.
// It could however affect performance, so it exists to tell the runner that this
// point in the pipeline needs a fusion break, to enable the pipeline to change it's
// degree of parallelism.
//
// The change of parallelism goes both ways. It could allow for larger batch sizes
// enable smaller batch sizes downstream if it is infact paralleizable.
//
// But for a single transform node per stage runner, we can elide it entirely,
// since the input collection and output collection types match.
// Get the input and output PCollections, there should only be 1 each.
if len(t.GetInputs()) != 1 {
panic("Expected single input PCollection in reshuffle: " + prototext.Format(t))
}
if len(t.GetOutputs()) != 1 {
panic("Expected single output PCollection in reshuffle: " + prototext.Format(t))
}
inColID := getOnlyValue(t.GetInputs())
outColID := getOnlyValue(t.GetOutputs())
// We need to find all Transforms that consume the output collection and
// replace them so they consume the input PCollection directly.
// We need to remove the consumers of the output PCollection.
toRemove := []string{}
// We need to force the consumers to be stage root,
// because reshuffle should be a fusion break.
forcedRoots := []string{}
for tid, t := range comps.GetTransforms() {
for li, gi := range t.GetInputs() {
if gi == outColID {
t.GetInputs()[li] = inColIDView on GitHub (pinned to 12126d8942)