HKUDS/Vibe-Trading · error · UsdMObservationError
Binance USD-M position reads are incoherent
Error message
Binance USD-M position reads are incoherent
What it means
Raised by _join_positions when the set of active position symbols reported by Binance USD-M Futures' account endpoint (v2/account or account) does not match the set from the position-risk endpoint (v2/positionRisk). The library cross-reads both endpoints and treats any disagreement in the *presence* of open positions as an incoherent snapshot, refusing to build the observation.
Source
Thrown at agent/src/trading/connectors/binance/usdm.py:157
):
raise UsdMObservationError("Binance USD-M account totals and USDT asset totals are incoherent")
return values
def _join_positions(
account: Mapping[str, Any],
position_risk: list[Any],
close_enough: CloseEnough,
) -> list[dict[str, Any]]:
account_rows = _mapping_rows(account.get("positions"), "account positions")
risk_rows = _mapping_rows(position_risk, "position risk")
_require_one_way(account_rows)
_require_one_way(risk_rows)
account_active = _active_by_symbol(account_rows, "account")
risk_active = _active_by_symbol(risk_rows, "position risk")
if set(account_active) != set(risk_active):
raise UsdMObservationError("Binance USD-M position reads are incoherent")
result: list[dict[str, Any]] = []
for raw_symbol in sorted(account_active):
account_row = account_active[raw_symbol]
risk_row = risk_active[raw_symbol]
quantity = _number(account_row.get("positionAmt"), "positionAmt")
risk_quantity = _number(risk_row.get("positionAmt"), "positionAmt")
entry_price = _number(account_row.get("entryPrice"), "entryPrice", positive=True)
risk_entry = _number(risk_row.get("entryPrice"), "entryPrice", positive=True)
if not math.isclose(quantity, risk_quantity, rel_tol=0, abs_tol=1e-12) or not math.isclose(
entry_price, risk_entry, rel_tol=0, abs_tol=1e-12
):
raise UsdMObservationError("Binance USD-M position reads are incoherent")
open_order_margins = (
_number(
account_row.get("openOrderInitialMargin"),
"openOrderInitialMargin",
non_negative=True,View on GitHub (pinned to 80ffdda44c)
Solutions
- Retry the observation after a short delay (e.g. 1-2s) so both endpoints converge
- Ensure no other bot/manual session trades this account while observations are read
- Check whether one endpoint was served from cache/stale data and force a fresh request
- Inspect the raw account_rows vs risk_rows symbol sets to confirm which side is stale
Example fix
// before
observation = await read_account_observation()
// after
for attempt in range(3):
try:
observation = await read_account_observation()
break
except UsdMObservationError:
if attempt == 2:
raise
await asyncio.sleep(1.5) Defensive patterns
Strategy: retry
Validate before calling
# fetch both endpoints and compare active symbol sets before observing
acct = await client.futures_account()
risk = await client.futures_position_risk()
a_syms = {p['symbol'] for p in acct['positions'] if float(p['positionAmt']) != 0}
r_syms = {p['symbol'] for p in risk if float(p['positionAmt']) != 0}
assert a_syms == r_syms, f"stale snapshot: {a_syms ^ r_syms}" Try / catch
try:
obs = await connector.read_account_observation()
except UsdMObservationError as e:
if "incoherent" in str(e):
await asyncio.sleep(1.5)
obs = await connector.read_account_observation()
else:
raise Prevention
- Read observations when the account is quiet (no in-flight orders/fills)
- Serialize observations with trading actions via a lock so they never overlap
- Retry transient incoherence once or twice before surfacing it
When it happens
Trigger: Calling read_account_observation while a position is being opened/closed/filled so one endpoint reflects the change before the other; querying the two endpoints non-atomically (sequentially, not via the same moment); a symbol with positionAmt != 0 on one endpoint but 0/absent on the other.
Common situations: Race conditions during concurrent manual trading on the same account, slow API replication between Binance's account and risk services, partial fills in flight, or a stale cached response from one of the two endpoints.
Related errors
- Binance USD-M Shadow Account supports USDT collateral only
- Binance USD-M margin mode is missing
- Binance USD-M isolated position requires positive isolated m
- Binance USD-M cross position must report zero isolated margi
- Binance USD-M assets must include exactly one USDT row
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/87444070ba2cf7f2.
Report an issue: GitHub.