apache/beam · error

panic(err)

Error message

panic(err)

What it means

newWriteFn panics when any WriteOptionsFn option function returns a non-nil error while building the write DoFn. Option constructors validate their inputs (e.g. batch size bounds) and surface failures here.

Solutions

  1. Fix the option values passed to Write, e.g. ensure the batch size is a positive integer.
  2. Validate option parameters at config-load time before building the pipeline.
  3. If using custom WriteOptionsFn implementations, return errors deliberately only for truly invalid input and fix the caller.

Example fix

// before
spannerio.Write(s, db, "users", col, spannerio.WriteBatchSize(cfg.BatchSize)) // 0
// after
if cfg.BatchSize <= 0 {
    cfg.BatchSize = 1000
}
spannerio.Write(s, db, "users", col, spannerio.WriteBatchSize(cfg.BatchSize))
Defensive patterns

Strategy: validation

Validate before calling

if batchSize <= 0 {
    return fmt.Errorf("write batch size must be positive, got %d", batchSize)
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        err = fmt.Errorf("invalid spanner write option: %v", r)
    }
}()

Prevention

When it happens

Trigger: Calling spannerio.Write with an invalid option value, e.g. a WriteOptionsFn constructed with a non-positive batch size.

Common situations: Batch size derived from config that can be 0 or negative, typos in option values, or hand-written option functions that return errors on unexpected inputs.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/io/spannerio/write.go:78

	beam.ParDo0(s, newWriteFn(db, table, col.Type().Type(), options...), col)
}

type writeFn struct {
	spannerFn
	Table     string           `json:"table"`   // The table to write to
	Type      beam.EncodedType `json:"type"`    // Type is the encoded schema type.
	Options   writeOptions     `json:"options"` // Spanner write options
	mutations []*spanner.Mutation
}

func newWriteFn(db string, table string, t reflect.Type, options ...WriteOptionsFn) *writeFn {
	writeOptions := writeOptions{
		BatchSize: 1000, // default
	}

	for _, opt := range options {
		if err := opt(&writeOptions); err != nil {
			panic(err)
		}
	}

	return &writeFn{spannerFn: newSpannerFn(db), Table: table, Type: beam.EncodedType{T: t}, Options: writeOptions}
}

func (f *writeFn) Setup(ctx context.Context) error {
	return f.spannerFn.Setup(ctx)
}

func (f *writeFn) Teardown() {
	f.spannerFn.Teardown()
}

func (f *writeFn) ProcessElement(ctx context.Context, value beam.X) error {
	mutation, err := spanner.InsertOrUpdateStruct(f.Table, value)
	if err != nil {
		return err

View on GitHub (pinned to 12126d8942)