apache/beam · error

failed to marshal receiver %v

Error message

failed to marshal receiver %v

What it means

encodeFn marshals the DoFn receiver value to JSON (via jsonx.Marshal) to embed in the Fn proto's Opt field; this error means that JSON marshaling of the user's DoFn struct failed. Usually the struct contains fields JSON cannot represent (channels, funcs, unexported-only state, cycles).

Source

Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:259

		t := reflect.TypeOf(u.Recv)
		k, ok := runtime.TypeKey(reflectx.SkipPtr(t))
		if !ok {
			err := errors.Errorf("failed to create TypeKey for receiver type %T", u.Recv)
			return nil, errors.WithContextf(err, "encoding structural DoFn %v", u)
		}
		if _, ok := runtime.LookupType(k); !ok {
			err := errors.Errorf("receiver type %v must be registered", t)
			return nil, errors.WithContextf(err, "encoding structural DoFn %v", u)
		}
		typ, err := encodeType(t)
		if err != nil {
			wrapped := errors.Wrapf(err, "failed to encode receiver type %T", u.Recv)
			return nil, errors.WithContextf(wrapped, "encoding structural DoFn %v", u)
		}

		data, err := jsonx.Marshal(u.Recv)
		if err != nil {
			wrapped := errors.Wrapf(err, "failed to marshal receiver %v", u.Recv)
			return nil, errors.WithContextf(wrapped, "encoding structural DoFn %v", u)
		}
		return &v1pb.Fn{Type: typ, Opt: string(data)}, nil

	default:
		return nil, errors.Errorf("failed to encode DoFn %v, missing fn", u)
	}
}

func decodeFn(u *v1pb.Fn) (*graph.Fn, error) {
	if u.Dynfn != nil {
		gen, err := runtime.ResolveFunction(u.Dynfn.Gen, genFnType)
		if err != nil {
			wrapped := errors.Wrapf(err, "bad symbol %v", u.Dynfn.Gen)
			return nil, errors.WithContextf(wrapped, "decoding dynamic DoFn %v", u)
		}

		t, err := decodeType(u.Dynfn.Type)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove func/chan/unserializable fields from the DoFn struct, or mark them `json:"-"` if they can be reconstructed.
  2. Move non-serializable state out of the DoFn and pass it via side inputs or closure-free configuration.
  3. Fix any custom MarshalJSON implementations on receiver fields.
  4. Keep DoFn receiver as a plain data struct with JSON-safe exported fields.

Example fix

// before
type myFn struct{ cb func(int) }

// after
type myFn struct {
    cb func(int) `json:"-"` // reinitialized in Setup()
}
Defensive patterns

Strategy: validation

Validate before calling

if _, err := json.Marshal(fn.Recv); err != nil {
    return fmt.Errorf("DoFn receiver not JSON-serializable: %w", err)
}

Type guard

func jsonSafe(v interface{}) bool { _, err := json.Marshal(v); return err == nil }

Try / catch

_, err := json.Marshal(recv)
if err != nil {
    return fmt.Errorf("DoFn %T not serializable: %w", recv, err)
}

Prevention

When it happens

Trigger: EncodeMultiEdge on a structural DoFn whose receiver contains a func, chan, complex number, cyclic reference, or a MarshalJSON implementation that errors.

Common situations: DoFn structs holding callback functions or channels for convenience; custom types with broken MarshalJSON methods; side-input state stored as unserializable fields.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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