apache/beam · error

cannot claim work after restriction tracker returns false

Error message

cannot claim work after restriction tracker returns false

What it means

The offsetrange.Tracker in Beam's Go SDK stops permanently once TryClaim returns false. This error is recorded when a claim is attempted on an already-stopped tracker, violating the restriction-tracker protocol which forbids claiming after a false return. The error is surfaced by the framework when the DoFn finishes.

Source

Thrown at sdks/go/pkg/beam/io/rtrackers/offsetrange/offsetrange.go:160

		claimed:   rest.Start - 1,
		attempted: -1,
		stopped:   false,
		err:       nil,
	}
}

// TryClaim accepts an int64 position representing the starting position of a block of work. It
// successfully claims it if the position is greater than the previously claimed position and within
// the restriction. Claiming a position at or beyond the end of the restriction signals that the
// entire restriction has been processed and is now done, at which point this method signals to end
// processing.
//
// The tracker stops with an error if a claim is attempted after the tracker has signalled to stop,
// if a position is claimed before the start of the restriction, or if a position is claimed before
// the latest successfully claimed.
func (tracker *Tracker) TryClaim(rawPos any) bool {
	if tracker.stopped {
		tracker.err = errors.New("cannot claim work after restriction tracker returns false")
		return false
	}

	pos := rawPos.(int64)
	tracker.attempted = pos
	if pos < tracker.rest.Start {
		tracker.stopped = true
		tracker.err = errors.New("position claimed is out of bounds of the restriction")
		return false
	}
	if pos <= tracker.claimed {
		tracker.stopped = true
		tracker.err = errors.New("cannot claim a position lower than the previously claimed position")
		return false
	}

	tracker.claimed = pos
	if pos >= tracker.rest.End {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Check the boolean return of TryClaim and break the loop immediately when it returns false.
  2. Use the rtrackers.RestrictiveTracker/TryClaim helper so claims are validated against the restriction and error paths handle stopping.
  3. Restructure ProcessElement so that each claimed position ends the current element and the next claim happens in a fresh invocation.

Example fix

// before
for pos := start; pos < end; pos++ {
    tracker.TryClaim(pos) // keeps claiming after tracker stopped
}
// after
for pos := start; pos < end; pos++ {
    if !tracker.TryClaim(pos) {
        return tracker.GetError()
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if tracker.IsDone() || tracker.GetError() != nil {
    return tracker.GetError() // do not attempt further claims
}

Type guard

func canClaim(t restrictiontracker.RestrictionTracker, pos int64) bool {
    return !t.IsDone() && t.GetError() == nil && t.TryClaim(pos)
}

Try / catch

if !tracker.TryClaim(pos) {
    return tracker.GetError() // stop; never claim again on this tracker
}

Prevention

When it happens

Trigger: Calling TryClaim again after a previous TryClaim returned false — e.g. a ProcessElement loop that keeps iterating after the tracker signalled completion (pos >= rest.End), or user code re-claiming without checking the boolean return.

Common situations: for loops using a condition that doesn't re-check tracker.TryClaim's false result; claiming a position beyond the restriction end (which stops the tracker) and then attempting another claim in the same element; retry wrappers that re-invoke claim logic on failure.

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/590375f8874a3aa1. Report an issue: GitHub.