apache/beam · error

plan failed with multiple errors

Error message

plan %v failed with multiple errors: %v

What it means

Plan.Down() tears down all units and aggregates every unit's Down() error. When more than one unit fails teardown, it returns this error listing all of them, signaling widespread cleanup failure in the plan.

Solutions

  1. Examine the list of aggregated errors to identify every failing unit
  2. Fix each underlying teardown failure (connectivity, permissions, double-close)
  3. Make unit Down() implementations idempotent and best-effort so teardown errors don't multiply
  4. Check for a shared root cause (lost network, revoked mount) rather than fixing units individually

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// Same as single-error case: idempotent, nil-tolerant Down in every unit

Try / catch

if err := plan.Down(); err != nil {
    for _, e := range multierr.Errors(err) { // aggregated errors
        log.Printf("unit teardown failed: %v", e)
    }
}

Prevention

When it happens

Trigger: Calling Plan.Down() when two or more units return non-nil errors from Down() — e.g. both a datasource and a sink failing cleanup, or multiple sinks failing to close.

Common situations: Worker shutdown under broken conditions (e.g. after network loss, multiple sinks fail to flush), failed deployments where credentials or mounts were revoked before teardown, or a process-wide resource failure hitting several units at once.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/exec/plan.go:230

	if p.getStatus() == Down {
		return nil // ok: already down
	}
	p.setStatus(Down)

	var errs []error
	for _, u := range p.units {
		if err := callNoPanic(ctx, u.Down); err != nil {
			errs = append(errs, err)
		}
	}

	switch len(errs) {
	case 0:
		return nil
	case 1:
		return errors.Wrapf(errs[0], "plan %v failed", p.id)
	default:
		return errors.Errorf("plan %v failed with multiple errors: %v", p.id, errs)
	}
}

func (p *Plan) String() string {
	var units []string
	for i := len(p.units) - 1; i >= 0; i-- {
		u := p.units[i]
		units = append(units, fmt.Sprintf("%v: %v", u.ID(), u))
	}
	return fmt.Sprintf("Plan[%v]:\n%v", p.ID(), strings.Join(units, "\n"))
}

// PlanSnapshot contains system metrics for the current run of the plan.
type PlanSnapshot struct {
	Source ProgressReportSnapshot
	PCols  []PCollectionSnapshot
}

View on GitHub (pinned to 12126d8942)