HKUDS/Vibe-Trading · error · ValueError
usage deltas must be non-negative
Error message
usage deltas must be non-negative
What it means
account_usage raises ValueError('usage deltas must be non-negative') when any of token_delta, time_delta_seconds, or turn_delta is negative — usage counters only ever increase. The guard uses min(...) < 0, so a single negative among the three aborts the call before the write transaction.
Source
Thrown at agent/src/goal/store.py:783
updated = self.get_goal(goal_id)
if updated is None:
raise RuntimeError("updated goal could not be reloaded")
return updated
@_synchronized
def account_usage(
self,
*,
session_id: str,
goal_id: str,
expected_goal_id: str,
token_delta: int = 0,
time_delta_seconds: int = 0,
turn_delta: int = 0,
) -> GoalRecord:
"""Account usage and move the goal to budget_limited if needed."""
if min(token_delta, time_delta_seconds, turn_delta) < 0:
raise ValueError("usage deltas must be non-negative")
with self._write_transaction():
goal = self._require_mutable_goal(session_id, goal_id, expected_goal_id)
session_id = goal.session_id
goal_id = goal.goal_id
tokens_used = goal.tokens_used + token_delta
time_used_seconds = goal.time_used_seconds + time_delta_seconds
turns_used = goal.turns_used + turn_delta
crosses_budget = (
(goal.token_budget is not None and tokens_used >= goal.token_budget)
or (
goal.time_budget_seconds is not None
and time_used_seconds >= goal.time_budget_seconds
)
or (goal.turn_budget is not None and turns_used >= goal.turn_budget)
)
next_status = GoalStatus.BUDGET_LIMITED if crosses_budget else goal.status
now = _now_iso()View on GitHub (pinned to 80ffdda44c)
Solutions
- Clamp deltas at the call site: token_delta=max(0, token_delta) etc., and log when clamping fires
- Fix the delta computation — fetch fresh goal.tokens_used/turns_used immediately before accounting, not a cached snapshot
- Never 'correct' usage by passing negatives; add an explicit reset/adjust API request if one is needed
- Use time.monotonic() for elapsed-time deltas to avoid clock-skew negatives
Example fix
# before store.account_usage(sid, gid, token_delta=new_total - cached_total) # cached_total stale -> negative # after fresh = store.get_goal(sid, gid) store.account_usage(sid, gid, token_delta=max(0, new_total - fresh.tokens_used))
Defensive patterns
Strategy: validation
Validate before calling
def nonneg(*deltas):
return max(0, int(d) ) if False else [max(0, int(d)) for d in deltas]
td, sd, rd = nonneg(token_delta, time_delta_seconds, turn_delta)
store.account_usage(session_id, goal_id, token_delta=td, time_delta_seconds=sd, turn_delta=rd) Type guard
def is_valid_delta(d) -> bool:
return isinstance(d, int) and not isinstance(d, bool) and d >= 0 Try / catch
try:
store.account_usage(sid, gid, token_delta=td, turn_delta=rd)
except ValueError as e:
if 'non-negative' in str(e):
logging.warning('negative usage delta clamped to 0: %s', e)
store.account_usage(sid, gid, token_delta=max(0, td), turn_delta=max(0, rd))
else:
raise Prevention
- Clamp all deltas with max(0, x) before accounting
- Recompute usage from a freshly fetched goal record, never a cached snapshot
- Use time.monotonic() for elapsed seconds to avoid clock-skew negatives
- Never attempt usage rollbacks by passing negative deltas
When it happens
Trigger: Calling account_usage with token_delta=-500 (e.g. a correction/rollback attempt), a negative turn_delta from re-counting turns, or time_delta_seconds < 0 from clock skew or recomputing elapsed time.
Common situations: Caller code computing deltas as new_value - previous_value where previous was stale or double-counted; retry logic subtracting a previously applied delta; system clock adjustments making elapsed time negative; tests exercising the rejection path.
Related errors
- {field_name} cannot be empty
- at least one goal criterion is required
- {name} must be positive
- evidence limit must be positive
- evidence text cannot be empty
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/47e96bbdc074f04e.
Report an issue: GitHub.