HKUDS/Vibe-Trading · error · ValueError
{label} must be non-negative, got {value!r}
Error message
{label} must be non-negative, got {value!r} What it means
waterfall_split requires distributable, contributed_capital, and preferred_amount to be non-negative; these are dollar magnitudes and a negative value would break every downstream tier calculation.
Source
Thrown at agent/src/quantlib/fundmath.py:1173
catch_up_rate: GP share of each catch-up dollar, in ``[0, 1]``. Pass
``0.0`` for a fund with no catch-up tier; any other value must
exceed ``carry_rate``, or the tier could never complete.
Returns:
A :class:`WaterfallResult` whose tiers sum exactly to ``distributable``.
Raises:
ValueError: If any amount is negative, if ``carry_rate`` is outside
``[0, 1)``, if ``catch_up_rate`` is outside ``[0, 1]``, or if a
non-zero ``catch_up_rate`` does not exceed ``carry_rate``.
"""
for label, value in (
("distributable", distributable),
("contributed_capital", contributed_capital),
("preferred_amount", preferred_amount),
):
if value < 0.0:
raise ValueError(f"{label} must be non-negative, got {value!r}")
if not 0.0 <= carry_rate < 1.0:
raise ValueError(f"carry_rate must be in [0, 1), got {carry_rate!r}")
if not 0.0 <= catch_up_rate <= 1.0:
raise ValueError(f"catch_up_rate must be in [0, 1], got {catch_up_rate!r}")
if catch_up_rate > 0.0 and catch_up_rate <= carry_rate:
raise ValueError(
f"catch_up_rate={catch_up_rate!r} must exceed carry_rate="
f"{carry_rate!r}, otherwise the catch-up tier can never complete. "
"Pass catch_up_rate=0.0 for a fund with no catch-up."
)
remaining = float(distributable)
return_of_capital = min(remaining, float(contributed_capital))
remaining -= return_of_capital
preferred_paid = min(remaining, float(preferred_amount))
remaining -= preferred_paidView on GitHub (pinned to 80ffdda44c)
Solutions
- Verify the sign convention: all three arguments are non-negative dollar amounts
- Clamp tiny negative floats from floating-point drift: max(0.0, value)
- Trace where the negative number originated (accrual, aggregation, or parse) and fix it
Example fix
# before
waterfall_split(distributable=dist, contributed_capital=paid, preferred_amount=pref) # pref=-1e-12
# after
waterfall_split(
distributable=max(0.0, dist),
contributed_capital=max(0.0, paid),
preferred_amount=max(0.0, pref),
) Defensive patterns
Strategy: validation
Validate before calling
distributable = max(0.0, distributable) contributed_capital = max(0.0, contributed_capital) preferred_amount = max(0.0, preferred_amount)
Prevention
- Establish one sign convention document for the pipeline
- Clamp float drift to zero before waterfall calls
When it happens
Trigger: Calling waterfall_split(distributable=-100.0, ...) or passing a negative preferred_amount computed by an accrual bug, via european_waterfall/_pooled_entitlement or directly in tests.
Common situations: Sign-convention mix-ups (treating distributions as negative); a preferred-return accrual that went negative; feeding gross instead of net values with offsets applied twice.
Related errors
- kind={self.kind!r} must have a {direction} amount under the
- latest valuation on {marks[-1].date} is {value!r}; a residua
- preferred rate must be non-negative, got {rate!r}
- tier {self.name!r} has a negative {label} of {value!r}
- tier {self.name!r} does not conserve cash: lp {self.lp_amoun
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/03eb68e0cc030631.
Report an issue: GitHub.