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

  1. Check for concurrent modification of pipeline component maps (data race) with the race detector (go run -race).
  2. Verify the beam binary was built from unmodified sources.
  3. 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

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


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)