HKUDS/Vibe-Trading · error · UsdMObservationError

Binance USD-M field {name} must be non-negative

Error message

Binance USD-M field {name} must be non-negative

What it means

Raised by _number when a field is numeric, finite, but negative while non_negative=True was requested (or via _integer which sets non_negative=True). Used for counts and amounts that can be zero but never negative, e.g. update indices, seat numbers, quantities. The {name} placeholder identifies the field.

Source

Thrown at agent/src/trading/connectors/binance/usdm.py:331


def _number(
    value: Any,
    name: str,
    *,
    non_negative: bool = False,
    positive: bool = False,
) -> float:
    try:
        number = float(value)
    except (TypeError, ValueError) as exc:
        raise UsdMObservationError(f"Binance USD-M field {name} must be numeric") from exc
    if not math.isfinite(number):
        raise UsdMObservationError(f"Binance USD-M field {name} must be finite")
    if positive and number <= 0:
        raise UsdMObservationError(f"Binance USD-M field {name} must be positive")
    if non_negative and number < 0:
        raise UsdMObservationError(f"Binance USD-M field {name} must be non-negative")
    return number


def _integer(value: Any, name: str) -> int:
    number = _number(value, name, non_negative=True)
    if not number.is_integer():
        raise UsdMObservationError(f"Binance USD-M field {name} must be an integer")
    return int(number)


def _configuration_hash(source_profile: str, host: str, absolute_tolerance: float) -> str:
    payload = {
        "schema_version": SCHEMA_VERSION,
        "source_profile": source_profile,
        "market_type": "usdm",
        "host": host,
        "account_endpoint": "/fapi/v2/account",
        "position_endpoint": "/fapi/v3/positionRisk",

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Inspect the named field in the raw payload; decide whether -1/negative is a sentinel meaning 'missing' and map it to None/0 before parsing
  2. Fix sign handling in upstream computations
  3. Update fixtures to non-negative values
  4. If the exchange legitimately returns -1 sentinels, translate them before calling the connector

Example fix

// before
_number(payload.get("updateTime"), "updateTime", non_negative=True)  # -1
// after
raw = payload.get("updateTime")
_number(0 if raw == -1 else raw, "updateTime", non_negative=True)
Defensive patterns

Strategy: validation

Validate before calling

def non_negative(v) -> float:
    n = float(v)
    if n < 0:
        raise ValueError(f"negative value: {v}")
    return n

payload["updateTime"] = max(0, payload.get("updateTime", 0))

Try / catch

try:
    obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
    if "must be non-negative" in str(exc):
        payload = translate_sentinels(payload)  # -1 -> 0/None
        obs = connector.read_account_observation(...)
    else:
        raise

Prevention

When it happens

Trigger: A field like updateTime, an index, or an amount is negative in the payload; e.g. positionAmt-style amounts extracted with non_negative=True, or a timestamp/count that underflowed.

Common situations: Sign flipped during upstream arithmetic; mock data with negative counts; API change returning -1 sentinels for 'not available'; timezone/epoch arithmetic producing negative timestamps.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/509ea4daaf6ee17a. Report an issue: GitHub.