apache/beam · error
size returned expected to be non-negative but received %v.
Error message
size returned expected to be non-negative but received %v.
What it means
In ProcessSizedElementsAndRestrictions.ProcessElement, the size function (sizeInv) invoked on the element and remaining restriction must return a non-negative size. A user-supplied Size() method returning a negative value is a contract violation, so the SDF aborts with this contextualized error.
Source
Thrown at sdks/go/pkg/beam/core/runtime/exec/sdf.go:214
ws := elm.Elm2.(*FullValue).Elm2
// If receiving directly from a datasource,
// the element may not be wrapped in a *FullValue
mainElm := convertIfNeeded(elm.Elm, &FullValue{})
splitRests, err := n.splitInv.Invoke(ctx, mainElm, rest)
if err != nil {
return err
}
for _, splitRest := range splitRests {
size, err := n.sizeInv.Invoke(ctx, mainElm, splitRest)
if err != nil {
return err
}
if size < 0 {
err := errors.Errorf("size returned expected to be non-negative but received %v.", size)
return errors.WithContextf(err, "%v", n)
}
output := &FullValue{}
output.Timestamp = elm.Timestamp
output.Windows = elm.Windows
output.Elm = &FullValue{Elm: mainElm, Elm2: &FullValue{Elm: splitRest, Elm2: ws}}
output.Elm2 = size
if err := n.Out.ProcessElement(ctx, output, values...); err != nil {
return err
}
}
return nil
}
// FinishBundle resets the invokers.View on GitHub (pinned to 12126d8942)
Solutions
- Fix the Size() method to return >= 0 for all valid element/restriction pairs
- Replace sentinel -1 returns with a proper default (e.g. 0 or an estimated size)
- Clamp the computed size: if size < 0 { size = 0 } (or fail fast with a descriptive error)
- Test Size() against edge-case elements (empty restrictions, zero-length payloads)
Example fix
// before
func (fn *myFn) Size(elm string, rest RangeRestriction) (float64, error) {
return int64(len(rest.End) - len(rest.Start)) // can be negative
}
// after
func (fn *myFn) Size(elm string, rest RangeRestriction) (float64, error) {
size := rest.End - rest.Start
if size < 0 {
return 0, fmt.Errorf("invalid restriction %v", rest)
}
return float64(size) * bytesPerElement, nil
} Defensive patterns
Strategy: validation
Validate before calling
// Guard inside the Size() implementation
func (fn *myFn) Size(elm string, rest RangeRestriction) (float64, error) {
size := rest.End - rest.Start
if size < 0 {
return 0, fmt.Errorf("invalid restriction %v: negative size", rest)
}
return float64(size), nil
} Type guard
func nonNegativeSize(s float64) float64 { if s < 0 { return 0 }; return s } Try / catch
if err := plan.Execute(ctx); err != nil {
if strings.Contains(err.Error(), "non-negative") {
log.Printf("Size() contract violated: %v", err)
}
return err
} Prevention
- Never return -1 as an 'unknown size' sentinel from Size()
- Unit-test Size() for empty restrictions and zero-length elements
- Compute sizes with unsigned/checked arithmetic to avoid underflow
- Clamp negative results to 0 as a last resort
When it happens
Trigger: A splittable DoFn whose Size() method (sizeFn) returns a negative value for a given element + restriction during ProcessElement — e.g. computing size from a byte length that underflowed or a lookup that returned -1 as a sentinel.
Common situations: Size() implementations using len() on data whose length computation underflows, returning -1 for 'unknown' size, or a size based on a restriction that is inverted/empty.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- not all required SplittableDoFn methods are present. Missing
- method %v has sdf.RTracker as param %v, expected none
- method %v missing sdf.RTracker, expected one at index %v
- DoFn terminated without fully processing restriction
- Restriction tracker missing.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/590a2b8b12ab9af0.
Report an issue: GitHub.