apache/beam · error

panic(formatParDoError(dofn, len(ret), 0))

Error message

panic(formatParDoError(dofn, len(ret), 0))

What it means

ParDo0 applies a ParDo transform that must produce exactly zero output PCollections. After TryParDo succeeds, if the number of returned PCollections is not 0, it panics with a formatted ParDo error describing the dofn and the actual vs expected output count.

Source

Thrown at sdks/go/pkg/beam/pardo.go:137

	var ret []PCollection
	for _, out := range edge.Output {
		c := PCollection{out.To}
		c.SetCoder(NewCoder(c.Type()))
		ret = append(ret, c)
	}
	return ret, nil
}

// ParDoN inserts a ParDo with any number of outputs into the pipeline.
func ParDoN(s Scope, dofn any, col PCollection, opts ...Option) []PCollection {
	return MustN(TryParDo(s, dofn, col, opts...))
}

// ParDo0 inserts a ParDo with zero output transform into the pipeline.
func ParDo0(s Scope, dofn any, col PCollection, opts ...Option) {
	ret := MustN(TryParDo(s, dofn, col, opts...))
	if len(ret) != 0 {
		panic(formatParDoError(dofn, len(ret), 0))
	}
}

// ParDo is the core element-wise PTransform in Apache Beam, invoking a
// user-specified function on each of the elements of the input PCollection
// to produce zero or more output elements, all of which are collected into
// the output PCollection. Use one of the ParDo variants for a different
// number of output PCollections. The PCollections do not need to have the
// same types.
//
// Elements are processed independently, and possibly in parallel across
// distributed cloud resources. The ParDo processing style is similar to what
// happens inside the "Mapper" or "Reducer" class of a MapReduce-style
// algorithm.
//
// # DoFns
//
// The function to use to process each element is specified by a DoFn, either as

View on GitHub (pinned to 12126d8942)

Solutions

  1. Change the DoFn to return no values (side-effect-only, e.g. via an output sink)
  2. Use beam.ParDo instead if the DoFn legitimately produces one output
  3. Match the ParDo0/ParDo/ParDoN variant to the DoFn's actual return arity

Example fix

// before
beam.ParDo0(s, func(x string) string { return x }, col) // 1 output, expects 0
// after
beam.ParDo(s, func(x string) string { return x }, col)
Defensive patterns

Strategy: type-guard

Validate before calling

// Check DoFn signature arity before applying
// A ParDo0 DoFn must produce no outputs (no return values beyond error conventions)

Type guard

func isZeroOutputDoFn(fn any) bool {
    t := reflect.TypeOf(fn)
    for t.Kind() == reflect.Ptr {
        t = t.Elem()
    }
    m, ok := t.MethodByName("ProcessElement")
    if !ok { return false }
    // heuristic: count emit params and return values against expected outputs
    return m.Type.NumOut() == 0
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        err = fmt.Errorf("ParDo0 arity mismatch: %v", r)
    }
}()

Prevention

When it happens

Trigger: Calling beam.ParDo0 with a DoFn whose signature yields one or more output PCollections (e.g. a function that returns a value) instead of returning nothing.

Common situations: Reusing a DoFn written for beam.ParDo/ParDo2 with ParDo0, or changing a DoFn's return signature after switching the apply call, causing a count mismatch.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/01da96fc4cbdc4b2. Report an issue: GitHub.