HKUDS/Vibe-Trading · error · ValueError
tier {self.name!r} has a negative {label} of {value!r}
Error message
tier {self.name!r} has a negative {label} of {value!r} What it means
Each waterfall tier's allocation dataclass validates in __post_init__ that amount, lp_amount, and gp_amount are non-negative (within _ALLOCATION_TOLERANCE). A negative allocation would corrupt the LP/GP split downstream.
Source
Thrown at agent/src/quantlib/fundmath.py:1026
amount: float
lp_amount: float
gp_amount: float
def __post_init__(self) -> None:
"""Check that the tier's two shares account for the whole tier.
Raises:
ValueError: If ``lp_amount + gp_amount`` differs from ``amount``, or
if any figure is negative. A waterfall that does not conserve
cash is a bug, never a rounding artefact worth tolerating.
"""
for label, value in (
("amount", self.amount),
("lp_amount", self.lp_amount),
("gp_amount", self.gp_amount),
):
if value < -_ALLOCATION_TOLERANCE:
raise ValueError(
f"tier {self.name!r} has a negative {label} of {value!r}"
)
if not math.isclose(
self.lp_amount + self.gp_amount,
self.amount,
rel_tol=_ALLOCATION_TOLERANCE,
abs_tol=_ALLOCATION_TOLERANCE,
):
raise ValueError(
f"tier {self.name!r} does not conserve cash: lp {self.lp_amount!r} "
f"+ gp {self.gp_amount!r} != {self.amount!r}"
)
@dataclass(frozen=True)
class WaterfallResult:
"""Outcome of a European whole-of-fund distribution waterfall.
View on GitHub (pinned to 80ffdda44c)
Solutions
- Clamp allocations to >= 0 (max(value, 0.0)) where a partial distribution legitimately yields zero
- Audit the upstream split computation for overshoot (remaining cash exhausted before a tier fills)
- Fix fixture data sign errors
Example fix
# before tier = Tier(name="catch_up", amount=amount, lp_amount=lp, gp_amount=gp) # gp < 0 on partial catch-up # after clamped = max(0.0, gp) tier = Tier(name="catch_up", amount=lp + clamped, lp_amount=lp, gp_amount=clamped)
Defensive patterns
Strategy: validation
Validate before calling
def safe_tier(name, lp, gp, tol=1e-9):
lp, gp = max(0.0, lp), max(0.0, gp)
return Tier(name=name, amount=lp + gp, lp_amount=lp, gp_amount=gp) Prevention
- Clamp sleeve values at zero in split builders
- Round allocations consistently before constructing tiers
When it happens
Trigger: Constructing a tier (e.g. WaterfallTier(name="catch-up", amount=-100.0, lp_amount=-60.0, gp_amount=-40.0)) with any negative field, or a builder that computes allocations which go negative on partial distributions.
Common situations: Rounding drift in generated tier splits; a carry/catch-up computation overshooting into negative remainders; hand-built fixtures with wrong signs.
Related errors
- waterfall does not reconcile on {label}: tiers give {compute
- tier {self.name!r} does not conserve cash: lp {self.lp_amoun
- {label} must be non-negative, got {value!r}
- carry_rate must be in [0, 1), got {carry_rate!r}
- catch_up_rate must be in [0, 1], got {catch_up_rate!r}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/29eb95b15c53f7cb.
Report an issue: GitHub.