apache/beam · error

Restriction tracker missing.

Error message

Restriction tracker missing.

What it means

ProcessSizedElementsAndRestrictions.Split performs a dynamic split of pending elements and restrictions, which requires the node's restriction tracker to be initialized. When n.rt is nil the node was never claimed/started, so Split returns this error wrapped with context about the split attempt.

Source

Thrown at sdks/go/pkg/beam/core/runtime/exec/sdf.go:678

// each case occurs and the implementation details, see the documentation for
// the singleWindowSplit and multiWindowSplit methods.
func (n *ProcessSizedElementsAndRestrictions) Split(ctx context.Context, f float64) ([]*FullValue, []*FullValue, error) {
	// Get the watermark state immediately so that we don't overestimate our current watermark.
	rWeState := n.wesInv.Invoke(n.PDo.we)
	pWeState := rWeState
	// If we've processed elements, the initial watermark estimator state will be set.
	// In that case we should hold the output watermark at that initial state so that we don't
	// Advance past where the current elements are holding the watermark
	if n.initWeS != nil {
		pWeState = n.initWeS
	}
	addContext := func(err error) error {
		return errors.WithContext(err, "Attempting split in ProcessSizedElementsAndRestrictions")
	}

	// Errors checking.
	if n.rt == nil {
		return nil, nil, addContext(errors.New("Restriction tracker missing."))
	}
	if err := n.rt.GetError(); err != nil {
		return nil, nil, addContext(err)
	}

	// Split behavior differs depending on whether this is a window-observing
	// DoFn or not.
	if len(n.elm.Windows) > 1 {
		p, r, err := n.multiWindowSplit(ctx, f, pWeState, rWeState)
		if err != nil {
			return nil, nil, addContext(err)
		}
		return p, r, nil
	}

	// Not window-observing, or window-observing but only one window.
	p, r, err := n.singleWindowSplit(ctx, f, pWeState, rWeState)
	if err != nil {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Only split/checkpoint after the SDF node has started processing and the tracker is set.
  2. Check rt != nil (or GetError) before invoking Split from runner-side code.
  3. Retry the split later once the bundle is actively processing.

Example fix

// before
if err := node.Split(fraction); err != nil { ... }
// after
if node.RTracker() == nil { return /* not yet splittable */ }
if err := node.Split(fraction); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

if node == nil || node.RTracker() == nil { return errors.New("cannot split: restriction tracker not initialized") }

Type guard

func splittable(n *exec.ProcessSizedElementsAndRestrictions) bool { return n != nil && n.RTracker() != nil }

Try / catch

res, pending, err := node.Split(fraction)
if err != nil && strings.Contains(err.Error(), "Restriction tracker missing") {
    // node not started yet: defer or retry the split
}

Prevention

When it happens

Trigger: Calling Split (typically via Checkpoint) on a ProcessSizedElementsAndRestrictions node whose restriction tracker field n.rt is still nil — i.e., splitting before any element processing initialized the tracker.

Common situations: Checkpointing a splittable stage before it has processed its first element; runner-side autoscaling/fission logic splitting freshly created SDF nodes; custom harness code invoking split during startup races.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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