HKUDS/Vibe-Trading · error · UsdMObservationError
Binance USD-M field {name} must be numeric
Error message
Binance USD-M field {name} must be numeric What it means
Raised by _number when a numeric field from an exchange payload cannot be converted with float(value) — i.e. it is None, a non-numeric string, or another non-numeric type. Every quantity/price/balance field extracted by the connector goes through this guard, so it fires on the first malformed field, naming it via {name} (e.g. positionAmt, walletBalance).
Source
Thrown at agent/src/trading/connectors/binance/usdm.py:325
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 = {View on GitHub (pinned to 80ffdda44c)
Solutions
- Log the offending row and field named in the message; confirm the field is present and a number in the raw response
- If fields were renamed in a newer Binance API version, map them before parsing
- Fix fixtures to include all required numeric fields
- Treat None-values that mean zero as "0" explicitly before calling if the business logic allows
Example fix
// before
row = {"symbol": "BTCUSDT"} # positionAmt missing -> None
_number(row.get("positionAmt"), "positionAmt")
// after
row = {"symbol": "BTCUSDT", "positionAmt": "0"}
_number(row.get("positionAmt"), "positionAmt") Defensive patterns
Strategy: type-guard
Validate before calling
def numeric_or_fail(row: dict, key: str):
v = row.get(key)
if v is None or isinstance(v, bool):
return None # caller decides default
try:
return float(v)
except (TypeError, ValueError):
return None
row["positionAmt"] = numeric_or_fail(row, "positionAmt") or 0.0 Type guard
def is_numeric_field(value: Any) -> TypeGuard[float | int | str]:
if isinstance(value, bool) or value is None:
return False
try:
float(value)
return True
except (TypeError, ValueError):
return False Try / catch
try:
obs = connector.read_account_observation(...)
except UsdMObservationError as exc:
if "must be numeric" in str(exc):
logger.error("malformed field in exchange payload: %s", exc)
drop_and_refetch()
raise Prevention
- Schema-validate exchange payloads (pydantic/jsonschema) before use
- Default missing numeric keys explicitly to 0 where semantically zero
- Pin the Binance API version the connector targets
When it happens
Trigger: A row passed to _account_values/_join_positions/_require_usdt_assets/_active_by_symbol/_integer has a numeric field that is None or non-numeric text; e.g. positionAmt missing (row.get returns None) or balance = 'N/A'.
Common situations: Binance omitting optional fields that are absent for isolated-margin accounts or new symbol types; mocks with missing keys; API version change renaming fields (e.g. marginBalance → totalMarginBalance); error envelopes where fields are absent.
Related errors
- Binance USD-M field {name} must be an integer
- Binance USD-M margin mode is missing
- Binance USD-M assets must include USDT
- Binance USD-M account totals are incoherent
- Binance USD-M {name} payload is invalid
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/8c8609de9f9a1370.
Report an issue: GitHub.