HKUDS/Vibe-Trading · error · UsdMObservationError

Binance USD-M field {name} must be positive

Error message

Binance USD-M field {name} must be positive

What it means

Raised by _number when a field is numeric and finite but <= 0 while positive=True was requested. This is used for quantities that must be strictly positive (e.g. leverage, quantities used as divisors). The {name} placeholder names the offending field so the caller can locate it in the payload.

Source

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

        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,
        "market_type": "usdm",
        "host": host,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check the field named in the message in the raw payload; confirm it should be > 0
  2. For genuinely unset fields, fetch them from the correct endpoint (e.g. real leverage from positionRisk/leverage) instead of a default 0
  3. Fix fixtures to use positive values
  4. Guard upstream computations against zero before passing results in

Example fix

// before
_number(row.get("leverage"), "leverage", positive=True)  # leverage == 0
// after
_number(row.get("leverage") or 1, "leverage", positive=True)
Defensive patterns

Strategy: validation

Validate before calling

def positive_or_none(row: dict, key: str) -> float | None:
    try:
        v = float(row.get(key))
    except (TypeError, ValueError):
        return None
    return v if v > 0 else None

lev = positive_or_none(row, "leverage") or fetch_leverage(symbol)

Try / catch

try:
    obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
    if "must be positive" in str(exc):
        logger.error("non-positive %s; refreshing symbol config", exc)
        refresh_symbol_meta()
    raise

Prevention

When it happens

Trigger: A field such as leverage or a size parameter is 0 or negative in the payload; e.g. leverage='0' on a symbol row, or a computed price/size collapsing to 0 due to an upstream bug.

Common situations: Exchange returning 0 leverage or 0 values for newly listed symbols before initialization; mocks defaulting numbers to 0; upstream rounding wiping out tiny positive values to 0; sign errors producing negative amounts.

Related errors


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