{"record":{"id":"17773da75a5df99a","repo":"HKUDS/Vibe-Trading","slug":"binance-usd-m-assets-must-include-exactly-one-usdt","errorCode":null,"errorMessage":"Binance USD-M assets must include exactly one USDT row","messagePattern":"Binance USD-M assets must include exactly one USDT row","errorType":"exception","errorClass":"UsdMObservationError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connectors/binance/usdm.py","lineNumber":248,"sourceCode":"def _require_usdt_assets(account: Mapping[str, Any]) -> Mapping[str, Any]:\n    assets = _mapping_rows(account.get(\"assets\"), \"assets\")\n    usdt_asset: Mapping[str, Any] | None = None\n    balance_fields = (\n        \"walletBalance\",\n        \"marginBalance\",\n        \"availableBalance\",\n        \"initialMargin\",\n        \"positionInitialMargin\",\n        \"openOrderInitialMargin\",\n        \"maintMargin\",\n        \"unrealizedProfit\",\n    )\n    for asset in assets:\n        symbol = str(asset.get(\"asset\") or \"\").upper()\n        balances = tuple(_number(asset.get(field), field) for field in balance_fields)\n        if symbol == \"USDT\":\n            if usdt_asset is not None:\n                raise UsdMObservationError(\"Binance USD-M assets must include exactly one USDT row\")\n            usdt_asset = asset\n        elif any(value != 0 for value in balances):\n            raise UsdMObservationError(\"Binance USD-M Shadow Account supports the USDT asset only\")\n    if usdt_asset is None:\n        raise UsdMObservationError(\"Binance USD-M assets must include USDT\")\n    return usdt_asset\n\n\ndef _require_coherent_totals(\n    account: Mapping[str, float],\n    positions: list[dict[str, Any]],\n    close_enough: CloseEnough,\n) -> None:\n    comparisons = (\n        (\n            account[\"total_unrealized_pnl\"],\n            sum(row[\"unrealized_pnl\"] for row in positions),\n        ),","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/binance/usdm.py#L230-L266","documentation":"The futures account assets array contained more than one row whose asset is USDT. The wallet model expects exactly one USDT balance row; duplicates make balances ambiguous.","triggerScenarios":"Binance returning the assets list with a repeated USDT entry (server-side anomaly), or a response assembled/merged from multiple requests (e.g. paginated or multi-account aggregation) duplicating the row.","commonSituations":"Custom middleware concatenating responses from v2/account and v3/account, retry logic appending instead of replacing the assets array, or mocking layers returning duplicated fixtures.","solutions":["Log the raw assets array and find the duplicate source","If merging responses in a wrapper, de-duplicate by asset symbol before passing data through","If Binance genuinely returned duplicates, retry the request and report the anomaly"],"exampleFix":"# before (wrapper merging two responses)\nassets = r1['assets'] + r2['assets']\n# after\nby_asset = {a['asset']: a for a in r1['assets'] + r2['assets']}\nassets = list(by_asset.values())","handlingStrategy":"validation","validationCode":"acct = await client.futures_account()\nusdt_rows = [a for a in acct['assets'] if a['asset'].upper() == 'USDT']\nif len(usdt_rows) != 1:\n    raise RuntimeError(f\"expected exactly 1 USDT row, got {len(usdt_rows)}\")","typeGuard":"def has_single_usdt_row(assets: list[dict]) -> bool:\n    return sum(1 for a in assets if str(a.get('asset', '')).upper() == 'USDT') == 1","tryCatchPattern":"try:\n    obs = await connector.read_account_observation()\nexcept UsdMObservationError as e:\n    if \"exactly one USDT row\" in str(e):\n        raise RuntimeError(\"response aggregation likely duplicated assets; fix wrapper\")\n    raise","preventionTips":["De-duplicate asset rows by symbol when merging responses in wrappers","Replace, never append, assets arrays across retries","Log raw assets when this fires to find the duplication source"],"tags":["binance","futures","assets","duplicate-row"],"backgroundTag":"duplicate-balance-row","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}