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
- Align OutputsMap entries with the actual number of edge outputs
- Regenerate the external transform payload with the current SDK
- Check OutboundTagToNode wiring so every tag maps to an output
- 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
- Keep OutputsMap in sync whenever a cross-language transform's outputs change
- Use expansion-service generated payloads rather than hand-written ones
- Add a unit test that marshals any custom external transform
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
- mismatch'd counts between External tags (%v) and inputs (%v)
- failed to expand cross language transform for edge: %v
- res.GetError()
- invalid scope
- unknown atomic type: %v
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/1116079c5dd96491.
Report an issue: GitHub.