{"record":{"id":"4aeb57d928ec9c89","repo":"apache/beam","slug":"cannot-claim-a-position-lower-than-the-previously-claimed","errorCode":null,"errorMessage":"cannot claim a position lower than the previously claimed position","messagePattern":"cannot claim a position lower than the previously claimed position","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/io/rtrackers/offsetrange/offsetrange.go","lineNumber":173,"sourceCode":"// The tracker stops with an error if a claim is attempted after the tracker has signalled to stop,\n// if a position is claimed before the start of the restriction, or if a position is claimed before\n// the latest successfully claimed.\nfunc (tracker *Tracker) TryClaim(rawPos any) bool {\n\tif tracker.stopped {\n\t\ttracker.err = errors.New(\"cannot claim work after restriction tracker returns false\")\n\t\treturn false\n\t}\n\n\tpos := rawPos.(int64)\n\ttracker.attempted = pos\n\tif pos < tracker.rest.Start {\n\t\ttracker.stopped = true\n\t\ttracker.err = errors.New(\"position claimed is out of bounds of the restriction\")\n\t\treturn false\n\t}\n\tif pos <= tracker.claimed {\n\t\ttracker.stopped = true\n\t\ttracker.err = errors.New(\"cannot claim a position lower than the previously claimed position\")\n\t\treturn false\n\t}\n\n\ttracker.claimed = pos\n\tif pos >= tracker.rest.End {\n\t\ttracker.stopped = true\n\t\treturn false\n\t}\n\treturn true\n}\n\n// GetError returns the error that caused the tracker to stop, if there is one.\nfunc (tracker *Tracker) GetError() error {\n\treturn tracker.err\n}\n\n// TrySplit splits at the nearest integer greater than the given fraction of the remainder. If the\n// fraction given is outside of the [0, 1] range, it is clamped to 0 or 1.","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/io/rtrackers/offsetrange/offsetrange.go#L155-L191","documentation":"offsetrange.Tracker.TryClaim enforces monotonic progress: each claimed position must be strictly greater than the last successfully claimed position. Attempting to claim an equal or lower position records this error and permanently stops the tracker, since Beam requires that claimed work never regresses.","triggerScenarios":"Calling TryClaim(pos) where pos <= tracker.claimed — e.g. retrying the same offset after a processing error, restarting iteration from the start, or advancing by 0 due to an increment bug.","commonSituations":"Retry logic inside ProcessElement that re-claims the same position on transient failure; loops with a non-advancing counter (increment outside the loop or conditional increments); reprocessing an element whose claimed position was already recorded.","solutions":["Ensure each TryClaim uses a strictly increasing position; advance the loop counter unconditionally.","Never retry a failed claim at the same position — return the tracker error and let the framework retry the whole element instead.","Restart iteration from tracker.claimed+1 (or the restriction start on a fresh tracker), not from a cached stale position."],"exampleFix":"// before\nfor pos := start; pos < end; pos++ {\n    if err := process(pos); err != nil {\n        continue // re-claims same pos next iteration pattern\n    }\n}\n// after\nfor pos := start; pos < end; pos++ {\n    if !tracker.TryClaim(pos) {\n        return tracker.GetError()\n    }\n    if err := process(pos); err != nil {\n        return err // framework retries whole element, new tracker\n    }\n}","handlingStrategy":"validation","validationCode":"if pos <= lastClaimed {\n    return fmt.Errorf(\"pos %d must be greater than last claimed %d\", pos, lastClaimed)\n}","typeGuard":null,"tryCatchPattern":"if !tracker.TryClaim(pos) {\n    return tracker.GetError() // monotonicity violation stops the tracker\n}","preventionTips":["Advance the position counter unconditionally in claim loops.","On processing failure, return the error instead of retrying the same claim.","Resume iteration from tracker's current claim state, never a cached position.","Write a test asserting each claimed position strictly increases."],"tags":["go","apache-beam","restriction-tracker","monotonic-progress"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}