HKUDS/Vibe-Trading · error · UsdMObservationError

Binance USD-M field {name} must be finite

Error message

Binance USD-M field {name} must be finite

What it means

Raised by _number when a field converts to float successfully but the result is not finite (NaN or +/-Inf). JSON parsers accept tokens like 'NaN'/'Infinity' or Python float('nan'), so this guard catches them before they poison downstream arithmetic. The {name} placeholder identifies which field (price, balance, positionAmt, etc.) is non-finite.

Source

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

def _canonical_symbol(symbol: str) -> str:
    if not symbol.endswith("USDT") or len(symbol) <= 4 or not symbol.isalnum():
        raise UsdMObservationError("Binance USD-M supports canonical */USDT symbols only")
    return f"{symbol[:-4]}-USDT-PERP"


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,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Trace where the NaN/Infinity originated — usually an upstream division by zero or unset field
  2. Sanitize inputs: convert non-finite values to a rejected/zero default before passing payloads to the connector
  3. Fix fixtures that use float('nan') or 'Infinity' strings
  4. If the exchange genuinely sent NaN, retry the snapshot and report to Binance if persistent

Example fix

// before
row = {"symbol": "BTCUSDT", "positionAmt": "NaN"}
// after
row = {"symbol": "BTCUSDT", "positionAmt": "0"}
Defensive patterns

Strategy: validation

Validate before calling

import math

def all_finite(row: dict, keys: list[str]) -> bool:
    return all(
        math.isfinite(float(row[k])) for k in keys if row.get(k) is not None
    )

if not all_finite(row, ["positionAmt", "entryPrice"]):
    row = sanitize(row)  # drop/zero non-finite values

Type guard

import math

def is_finite_number(value: Any) -> TypeGuard[float]:
    try:
        return math.isfinite(float(value))
    except (TypeError, ValueError):
        return False

Try / catch

try:
    obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
    if "must be finite" in str(exc):
        row = coerce_non_finite_to_zero(row)
        obs = connector.read_account_observation(...)  # retry with sanitized data
    else:
        raise

Prevention

When it happens

Trigger: A payload field is the string 'NaN' or 'Infinity' (Python's float() accepts these), or a computed/upstream value already containing NaN is fed back into the connector.

Common situations: Upstream components dividing by zero to produce NaN/inf and passing it along; exchange sending literal NaN in rare degenerate snapshots; fixtures using float('nan'); string interpolation of 'Infinity' from log-adjacent code.

Related errors


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