apache/beam · error

node %v in graph has undefined coder

Error message

node %v in graph has undefined coder

What it means

Graph.Build() finalizes the Beam DAG and verifies every node has a coder (the serialization spec for its element type). During expansion/translation Beam normally assigns coders automatically; a nil coder means graph construction left a node untyped, so Build refuses to proceed with 'node %v in graph has undefined coder'.

Source

Thrown at sdks/go/pkg/beam/core/graph/graph.go:91

	if !typex.IsBound(t) {
		panic(fmt.Sprintf("Node type not bound: %v", t))
	}
	id := len(g.nodes) + 1
	n := &Node{id: id, t: t, w: w, bounded: bounded}
	g.nodes = append(g.nodes, n)
	return n
}

// Build performs finalization on the graph. It verifies the correctness of the
// graph structure, typechecks the plan and returns a slice of the edges in
// the graph.
func (g *Graph) Build() ([]*MultiEdge, []*Node, error) {
	// Build a map of all nodes listed in g.nodes.
	nodes := make(map[*Node]bool)
	for _, n := range g.nodes {
		nodes[n] = true
		if n.Coder == nil {
			return nil, nil, errors.Errorf("node %v in graph has undefined coder", n.id)
		}
	}
	// Build a map of all nodes that are reachable by g.edges.
	reachable := make(map[*Node]*MultiEdge)
	for _, e := range g.edges {
		for _, i := range e.Input {
			reachable[i.From] = e
		}
		for _, o := range e.Output {
			reachable[o.To] = e
		}
	}
	for n := range nodes {
		if _, ok := reachable[n]; !ok {
			return nil, nil, errors.Errorf("node %v in graph is unconnected", n.id)
		}
	}
	for n, e := range reachable {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Find the DoFn/transform producing that node and give ProcessElement concrete encodable types (no interface{}, func, or chan).
  2. If using the low-level graph API, set n.Coder explicitly before Build().
  3. Check for a Beam SDK bug — search the error's node id against your pipeline; upgrade to the latest Beam release.
  4. Register custom types with beam.Encoder/coder registration so inference succeeds.
Defensive patterns

Strategy: try-catch

Try / catch

if _, _, err := g.Build(); err != nil {
    if strings.Contains(err.Error(), "undefined coder") {
        // inspect node id, fix producing DoFn types or set Coder explicitly
        log.Fatalf("coder inference failed: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling g.Build() after adding edges whose input/output nodes were never given a coder, typically from custom transform construction (beam.Create with unsupported types, custom DoFn signatures Beam can't infer, or manually assembled Graphs).

Common situations: Using a custom DoFn whose ProcessElement parameter type can't be encoded (e.g. interface{}, chan, func types); building nodes directly via the low-level graph API without setting Coder; SDK/runner bugs when inserting cross-language transforms.

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


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