apache/beam · error

mismatch'd counts between External tags (%v) and inputs (%v)

Error message

mismatch'd counts between External tags (%v) and inputs (%v)

What it means

For graph.External edges, the External payload declares an InputsMap of tags. If the number of tags in InputsMap doesn't equal the number of actual input edges on the graph node, the mapping is inconsistent and addMultiEdge aborts via handleErr, reporting both counts.

Source

Thrown at sdks/go/pkg/beam/core/runtime/graphx/translate.go:690

		spec = &pipepb.FunctionSpec{Urn: URNGBK}

	case graph.WindowInto:
		windowFn, err := makeWindowFn(edge.Edge.WindowFn)
		if err != nil {
			return handleErr(err)
		}
		payload := &pipepb.WindowIntoPayload{
			WindowFn: windowFn,
		}
		spec = &pipepb.FunctionSpec{Urn: URNWindow, Payload: protox.MustEncode(payload)}

	case graph.External:
		pyld := edge.Edge.Payload
		spec = &pipepb.FunctionSpec{Urn: pyld.URN, Payload: pyld.Data}

		if len(pyld.InputsMap) != 0 {
			if got, want := len(pyld.InputsMap), len(edge.Edge.Input); got != want {
				return handleErr(errors.Errorf("mismatch'd counts between External tags (%v) and inputs (%v)", got, want))
			}
			inputs = make(map[string]string)
			for tag, in := range InboundTagToNode(pyld.InputsMap, edge.Edge.Input) {
				if _, err := m.addNode(in); err != nil {
					return handleErr(err)
				}
				inputs[tag] = nodeID(in)
			}
		}

		if len(pyld.OutputsMap) != 0 {
			if got, want := len(pyld.OutputsMap), len(edge.Edge.Output); got != want {
				return handleErr(errors.Errorf("mismatch'd counts between External tags (%v) and outputs (%v)", got, want))
			}
			outputs = make(map[string]string)
			for tag, out := range OutboundTagToNode(pyld.OutputsMap, edge.Edge.Output) {
				if _, err := m.addNode(out); err != nil {
					return handleErr(err)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Rebuild the External transform with a correctly sized InputsMap matching the input count
  2. Regenerate the external payload with a matching SDK/runner version
  3. Check InboundTagToNode inputs: each tag must correspond to one edge input
  4. If hand-writing cross-language transforms, verify tag names and counts in the payload

Example fix

// before
pyld := graph.Payload{URN: urn, InputsMap: map[string]int{"a":0}} // 1 tag, 2 inputs
// after
pyld := graph.Payload{URN: urn, InputsMap: map[string]int{"a":0,"b":1}}
Defensive patterns

Strategy: validation

Validate before calling

// Before marshalling external transforms, validate tag/input arity
if len(pyld.InputsMap) != 0 && len(pyld.InputsMap) != len(edge.Input) {
    return fmt.Errorf("external %q: %d tags vs %d inputs", pyld.URN, len(pyld.InputsMap), len(edge.Input))
}

Try / catch

if _, err := graphx.Marshal(p); err != nil {
    if strings.Contains(err.Error(), "External tags") && strings.Contains(err.Error(), "inputs") {
        return fmt.Errorf("external transform payload inconsistent: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Marshalling a pipeline containing an External transform (cross-language / expansion payload) whose pyld.InputsMap length differs from len(edge.Edge.Input) — e.g. the external payload was constructed with mismatched tag lists.

Common situations: Building External transforms by hand with wrong inputs map; cross-language transforms whose payload was generated by an older runner SDK; custom I/O connectors with changed arity between versions.

Related errors


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