apache/beam · error

Primary restriction %#v is not done. Check that the RTracker

Error message

Primary restriction %#v is not done. Check that the RTracker's TrySplit() at fraction 0.0 returns a completed primary restriction

What it means

During SDF checkpointing, TrySplit at fraction 0.0 is used to split off the entire remaining restriction; after a successful split the primary (current) restriction must be done. If the restriction tracker reports !IsDone() after such a split, the tracker violates the SDF contract and this error is raised.

Source

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

	return p, r, nil
}

// Checkpoint splits the remaining work in a restriction into residuals to be resumed
// later by the runner. This is done iff the underlying Splittable DoFn returns a resuming
// ProcessContinuation. If the split occurs and the primary restriction is marked as done
// my the RTracker, the Checkpoint fails as this is a potential data-loss case.
func (n *ProcessSizedElementsAndRestrictions) Checkpoint(ctx context.Context) ([]*FullValue, error) {
	addContext := func(err error) error {
		return errors.WithContext(err, "Attempting checkpoint in ProcessSizedElementsAndRestrictions")
	}
	_, r, err := n.Split(ctx, 0.0)

	if err != nil {
		return nil, addContext(err)
	}

	if !n.rt.IsDone() {
		return nil, addContext(errors.Errorf("Primary restriction %#v is not done. Check that the RTracker's TrySplit() at fraction 0.0 returns a completed primary restriction", n.rt))
	}

	return r, nil
}

// singleWindowSplit is intended for splitting elements in non window-observing
// DoFns (or single-window elements in window-observing DoFns, since the
// behavior is identical). A single restriction split will occur and all windows
// present in the unsplit element will be present in both the resulting primary
// and residual.
func (n *ProcessSizedElementsAndRestrictions) singleWindowSplit(ctx context.Context, f float64, pWeState, rWeState any) ([]*FullValue, []*FullValue, error) {
	if n.rt.IsDone() { // Not an error, but not splittable.
		return []*FullValue{}, []*FullValue{}, nil
	}

	p, r, err := n.rt.TrySplit(f)
	if err != nil {
		return nil, nil, err

View on GitHub (pinned to 12126d8942)

Solutions

  1. Fix the custom RestrictionTracker's TrySplit so fraction 0.0 returns a primary restriction for which IsDone() is true
  2. Verify IsDone() semantics: it must return true when the remaining restriction contains no work
  3. Add unit tests: TrySplit(0.0) then assert primary.IsDone()
  4. Use beam.TrySplit/RTrackerContracts test helpers to validate tracker behavior before deployment

Example fix

// before: fraction 0.0 keeps work in primary
func (t *myTracker) TrySplit(fraction float64) (primary, rest interface{}, ok bool) {
    split := t.start + int64(fraction*float64(t.end-t.start))
    return Range{t.start, split}, Range{split, t.end}, true
}
// after
func (t *myTracker) TrySplit(fraction float64) (primary, rest interface{}, ok bool) {
    if fraction == 0.0 {
        return Range{t.start, t.end}, nil, true // primary covers everything => done
    }
    split := t.start + int64(fraction*float64(t.end-t.start))
    return Range{t.start, split}, Range{split, t.end}, true
}
Defensive patterns

Strategy: validation

Validate before calling

// Contract self-check for custom trackers
func checkTracker(t beam.RestrictionTracker) error {
    p, _, ok := t.TrySplit(0.0)
    if !ok { return errors.New("split at 0.0 failed") }
    _ = p
    return nil // ensure primary would report IsDone()==true
}

Try / catch

if err := plan.Execute(ctx); err != nil {
    if strings.Contains(err.Error(), "Primary restriction") {
        log.Printf("RestrictionTracker contract violation: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Checkpoint() when the custom RestrictionTracker's TrySplit(0.0) returns a primary restriction that is not complete — i.e. a user-implemented TrySplit does not follow the contract that splitting at fraction 0.0 yields a fully-done primary.

Common situations: Custom RestrictionTracker implementations where TrySplit mishandles fraction 0.0 (returns a partial primary), off-by-one restriction arithmetic, or a tracker whose IsDone doesn't agree with its split behavior.

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/6672f74df16a3a3c. Report an issue: GitHub.