apache/beam · critical
unreachable
Error message
unreachable
What it means
The final panic("unreachable") in getOnlyPair is a defensive fallthrough: after asserting len(in)==1, the for-range return should always exit the function. Reaching this line means the length check passed but iteration yielded nothing — theoretically impossible for a non-empty map, signaling severe compiler/runtime or state corruption.
Solutions
- Check for concurrent modification of pipeline component maps (data race) with the race detector (go run -race).
- Verify the beam binary was built from unmodified sources.
- If reproducible, report to the Beam project with build details.
Defensive patterns
Strategy: try-catch
Try / catch
defer func() {
if r := recover(); r != nil {
log.Fatalf("prism internal panic: %v\n%s", r, debug.Stack())
}
}() Prevention
- Run with -race to detect map mutation races
- Build prism from unmodified sources
- Report reproducible cases upstream with stack traces
When it happens
Trigger: Only reachable if the earlier len check is bypassed or the map is mutated concurrently between the check and the range loop.
Common situations: Practically never hit by users; appears in stack traces only due to genuine bugs, data races on pipeline components, or binary/codegen anomalies.
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
- expected single value map, had
- broken invariant: idsFound map is nil, but idsRequired map…
- Creating CustomCoder for type failed
- panic(err) propagating lpUnknownCoders error
- prism consistency error: trying to remove a non-existent…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/e9104acb0e4c80a0.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/runners/prism/internal/execute.go:430
}
func getWindowValueCoders(comps *pipepb.Components, col *pipepb.PCollection, coders map[string]*pipepb.Coder) (engine.WinCoderType, exec.WindowDecoder, exec.WindowEncoder) {
ws := comps.GetWindowingStrategies()[col.GetWindowingStrategyId()]
wcID, err := lpUnknownCoders(ws.GetWindowCoderId(), coders, comps.GetCoders())
if err != nil {
panic(err)
}
return makeWindowCoders(coders[wcID])
}
func getOnlyPair[K comparable, V any](in map[K]V) (K, V) {
if len(in) != 1 {
panic(fmt.Sprintf("expected single value map, had %v - %v", len(in), in))
}
for k, v := range in {
return k, v
}
panic("unreachable")
}
func getOnlyValue[K comparable, V any](in map[K]V) V {
_, v := getOnlyPair(in)
return v
}
// buildTrigger converts the protocol buffer representation of a trigger
// to the engine representation.
func buildTrigger(tpb *pipepb.Trigger) engine.Trigger {
switch at := tpb.GetTrigger().(type) {
case *pipepb.Trigger_AfterAll_:
subTriggers := make([]engine.Trigger, 0, len(at.AfterAll.GetSubtriggers()))
for _, st := range at.AfterAll.GetSubtriggers() {
subTriggers = append(subTriggers, buildTrigger(st))
}
return &engine.TriggerAfterAll{SubTriggers: subTriggers}
case *pipepb.Trigger_AfterAny_:View on GitHub (pinned to 12126d8942)