apache/beam · error
unexpected opcode
Error message
unexpected opcode: %v
What it means
During pipeline graph marshalling (graphx/translate.go), addMultiEdge converts each in-memory MultiEdge's Operation opcode into a Beam runner-API transform payload. The 'default' branch of the opcode switch is reached when the opcode is not one of the recognized ones (ParDo, GBK, CoGBK, Reshuffle, External, etc.), so the marshaller fails fast with 'unexpected opcode'. This indicates an operation kind the translator does not know how to serialize.
Solutions
- Update translate.go's opcode switch in addMultiEdge to handle the new graph.Op value and emit the appropriate pipepb transform payload
- Verify the pipeline is built with public beam APIs; manually constructed graphs may carry invalid opcodes
- Check Go SDK version: code written against a newer graph.Op enum running with an older translate.go needs upgrading
- File/report upstream to apache/beam if the op is a standard one that should be supported
Example fix
// before (translate.go addMultiEdge switch)
default:
err := errors.Errorf("unexpected opcode: %v", edge.Edge.Op)
return handleErr(err)
// after
case graph.MyNewOp:
return m.expandMyNewOp(edge)
default:
err := errors.Errorf("unexpected opcode: %v", edge.Edge.Op)
return handleErr(err) Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: only known ops can be marshalled
known := map[graph.Op]bool{graph.ParDo: true, graph.CoGBK: true, graph.Reshuffle: true, graph.External: true}
if !known[edge.Edge.Op] {
return fmt.Errorf("op %v not supported by graphx marshaller", edge.Edge.Op)
} Type guard
func isKnownOp(op graph.Op) bool {
switch op {
case graph.ParDo, graph.CoGBK, graph.Reshuffle, graph.External:
return true
}
return false
} Prevention
- Build pipelines only with public beam APIs, never hand-rolled graphs
- When adding new graph.Op values, update translate.go in the same change
- Keep the Go SDK at the version matching your pipeline construction code
When it happens
Trigger: A MultiEdge whose edge.Op is a new/unhandled graph.Op value reaches Marshal — e.g. a custom or newly added Operation type in the beam graph package that translate.go's switch has not been extended for, or a manually constructed graph passed to graphx.Marshal.
Common situations: Developers hacking on Beam internals adding a new operation kind without updating the marshaller; running a fork of the Go SDK where an op was introduced but translation support wasn't; building synthetic pipelines programmatically with an invalid op.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- AfterProcessingTime trigger set without a delay or…
- array len mismatch. decoding
- At least one subtrigger required for composite triggers.
- attempted to add namespace to missing coder id
- attempted to add namespace to missing windowing strategy id
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/55cb913241d09c44.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/translate.go:715
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()
}
transform := &pipepb.PTransform{
UniqueName: edge.Name,
Spec: spec,
Inputs: inputs,
Outputs: outputs,
EnvironmentId: transformEnvID,
Annotations: annotations,
}
m.transforms[id] = transform
allPIds = append(allPIds, id)View on GitHub (pinned to 12126d8942)