apache/beam · error

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

Error message

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

What it means

Same consistency check as inputs but for outputs: an External edge's OutputsMap tag count must equal the number of output PCollections on the edge. A mismatch means the external payload's declared outputs don't line up with the graph, so the marshaller returns this error via handleErr.

Source

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

		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)
				}
				outputs[tag] = nodeID(out)
			}
		}

	default:
		err := errors.Errorf("unexpected opcode: %v", edge.Edge.Op)
		return handleErr(err)
	}

	var transformEnvID = ""
	if !(spec.Urn == URNGBK || spec.Urn == URNImpulse) {
		transformEnvID = m.addDefaultEnv()

View on GitHub (pinned to 12126d8942)

Solutions

  1. Align OutputsMap entries with the actual number of edge outputs
  2. Regenerate the external transform payload with the current SDK
  3. Check OutboundTagToNode wiring so every tag maps to an output
  4. If the transform arity changed, update the expansion payload and inputs map together

Example fix

// before
pyld := graph.Payload{URN: urn, OutputsMap: map[string]int{"out":0}} // 1 tag, 2 outputs
// after
pyld := graph.Payload{URN: urn, OutputsMap: map[string]int{"out":0,"metrics":1}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate output tag arity before marshalling
if len(pyld.OutputsMap) != 0 && len(pyld.OutputsMap) != len(edge.Output) {
    return fmt.Errorf("external %q: %d tags vs %d outputs", pyld.URN, len(pyld.OutputsMap), len(edge.Output))
}

Try / catch

if _, err := graphx.Marshal(p); err != nil {
    if strings.Contains(err.Error(), "External tags") && strings.Contains(err.Error(), "outputs") {
        return fmt.Errorf("external output map mismatch: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Marshalling an External transform where len(pyld.OutputsMap) != len(edge.Edge.Output) — the payload declares more or fewer output tags than the graph node actually produces.

Common situations: Hand-crafted external payloads with wrong output arity; version drift in cross-language transforms where output schema changed; custom connectors with multiple outputs added/removed.

Related errors


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