{"record":{"id":"9e2005e0a7c63c6a","repo":"apache/beam","slug":"param-rangeendestimator-cannot-be-nil-implementing","errorCode":null,"errorMessage":"param rangeEndEstimator cannot be nil. Implementing offsetrange.RangeEndEstimator may be required","messagePattern":"param rangeEndEstimator cannot be nil\\. Implementing offsetrange\\.RangeEndEstimator may be required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/io/rtrackers/offsetrange/offsetrange.go","lineNumber":274,"sourceCode":"// of block positions if needed.\ntype GrowableTracker struct {\n\tTracker\n\trangeEndEstimator RangeEndEstimator\n}\n\n// NewGrowableTracker creates a GrowableTracker for handling a growable offset range.\n// math.MaxInt64 is used as the end of the range to indicate infinity for an unbounded range.\n//\n// An OffsetRange is considered growable when the end offset could grow (or change)\n// during execution time (e.g. Kafka topic partition offset, appended file, ...).\n//\n// The growable range is marked as done by claiming math.MaxInt64-1.\n//\n// For bounded restrictions, this tracker works the same as offsetrange.Tracker.\n// Use that directly if you have no need of estimating the end of a bound.\nfunc NewGrowableTracker(rest Restriction, rangeEndEstimator RangeEndEstimator) (*GrowableTracker, error) {\n\tif rangeEndEstimator == nil {\n\t\treturn nil, fmt.Errorf(\"param rangeEndEstimator cannot be nil. Implementing offsetrange.RangeEndEstimator may be required\")\n\t}\n\treturn &GrowableTracker{*NewTracker(Restriction{Start: rest.Start, End: rest.End}), rangeEndEstimator}, nil\n}\n\n// Start returns the starting range of the restriction tracked by a tracker.\nfunc (tracker *GrowableTracker) Start() int64 {\n\treturn tracker.GetRestriction().(Restriction).Start\n}\n\n// End returns the end range of the restriction tracked by a tracker.\nfunc (tracker *GrowableTracker) End() int64 {\n\treturn tracker.GetRestriction().(Restriction).End\n}\n\nfunc max(x, y int64) int64 {\n\tif x > y {\n\t\treturn x\n\t}","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/io/rtrackers/offsetrange/offsetrange.go#L256-L292","documentation":"NewGrowableTracker creates a restriction tracker for restrictions whose end may grow over time (e.g. an unbounded source). Because a growable tracker cannot estimate its end without a RangeEndEstimator, passing a nil estimator is rejected outright with this error. This is a defensive argument check in the Beam Go SDK.","triggerScenarios":"Calling offsetrange.NewGrowableTracker(rest, nil) — e.g. in a custom source's createRTracker when the developer omits the estimator — or in tests exercising bad-parameter paths.","commonSituations":"Implementing a custom unbounded/growing DoFn or source in Beam Go and forgetting to supply an offsetrange.RangeEndEstimator implementation; copying example code that uses the regular offsetrange.NewTracker and swapping to NewGrowableTracker without the extra argument being meaningful.","solutions":["Pass a non-nil RangeEndEstimator: implement EstimateEnded func(rest Restriction) bool (and RangeEndEstimatorFromRestrictionFn if needed) matching your restriction semantics.","If your restriction is actually bounded and static, use offsetrange.NewTracker(rest) instead, which requires no estimator.","For bounded restrictions with a growable tracker, you can use offsetrange.RangeEndEstimatorFromRestrictionFn(func(Restriction) bool { return true }) to treat them as ended.","Guard the call site: only construct NewGrowableTracker when the source can genuinely grow."],"exampleFix":"// before\ntracker, err := offsetrange.NewGrowableTracker(rest, nil)\n\n// after\ntracker, err := offsetrange.NewGrowableTracker(rest,\n    offsetrange.RangeEndEstimatorFromRestrictionFn(func(r offsetrange.Restriction) bool {\n        return r.End == math.MaxInt64 // reached the true end\n    }))","handlingStrategy":"validation","validationCode":"if estimator == nil {\n    return errors.New(\"offsetrange.NewGrowableTracker requires a non-nil RangeEndEstimator\")\n}\ntracker, err := offsetrange.NewGrowableTracker(rest, estimator)","typeGuard":"func estimatorOk(e offsetrange.RangeEndEstimator) bool { return e != nil }","tryCatchPattern":null,"preventionTips":["Use NewTracker for bounded restrictions; reserve NewGrowableTracker for truly growing restrictions.","Wrap tracker construction in a helper that supplies a default estimator so callers can't pass nil.","Add a unit test exercising tracker creation for every custom source."],"tags":["beam-go","restriction-tracker","nil-argument","splittable-dofn"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}