{"record":{"id":"d4db00b4d50197c4","repo":"HKUDS/Vibe-Trading","slug":"binance-usd-m-cross-position-must-report-zero-isol","errorCode":null,"errorMessage":"Binance USD-M cross position must report zero isolated margin","messagePattern":"Binance USD-M cross position must report zero isolated margin","errorType":"exception","errorClass":"UsdMObservationError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connectors/binance/usdm.py","lineNumber":208,"sourceCode":"            if not close_enough(\n                _number(account_row.get(account_field), account_field),\n                _number(risk_row.get(risk_field), risk_field),\n            ):\n                raise UsdMObservationError(\"Binance USD-M position reads are incoherent\")\n        if str(risk_row.get(\"marginAsset\") or \"\").upper() != \"USDT\":\n            raise UsdMObservationError(\"Binance USD-M Shadow Account supports USDT collateral only\")\n        isolated = account_row.get(\"isolated\")\n        if not isinstance(isolated, bool):\n            raise UsdMObservationError(\"Binance USD-M margin mode is missing\")\n        isolated_margin = _number(\n            risk_row.get(\"isolatedMargin\"),\n            \"isolatedMargin\",\n            non_negative=True,\n        )\n        if isolated and isolated_margin == 0:\n            raise UsdMObservationError(\"Binance USD-M isolated position requires positive isolated margin\")\n        if not isolated and isolated_margin != 0:\n            raise UsdMObservationError(\"Binance USD-M cross position must report zero isolated margin\")\n        result.append(\n            {\n                \"symbol\": _canonical_symbol(raw_symbol),\n                \"quantity\": quantity,\n                \"entry_price\": entry_price,\n                \"leverage\": _number(account_row.get(\"leverage\"), \"leverage\", positive=True),\n                \"margin_mode\": \"isolated\" if isolated else \"cross\",\n                \"isolated_margin\": isolated_margin if isolated else None,\n                \"unrealized_pnl\": _number(risk_row.get(\"unRealizedProfit\"), \"unRealizedProfit\"),\n                \"initial_margin\": _number(\n                    risk_row.get(\"positionInitialMargin\"),\n                    \"positionInitialMargin\",\n                    non_negative=True,\n                ),\n                \"maintenance_margin\": _number(risk_row.get(\"maintMargin\"), \"maintMargin\", non_negative=True),\n                \"update_time\": _integer(risk_row.get(\"updateTime\"), \"updateTime\"),\n            }\n        )","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/binance/usdm.py#L190-L226","documentation":"The inverse invariant: a cross-margin position (isolated=false) must report isolatedMargin == 0. Any non-zero isolatedMargin on a cross position means the data is inconsistent and the snapshot is rejected.","triggerScenarios":"A position switched from isolated to cross while stale risk data still carries the old isolatedMargin value; mid-transition reads; Binance service lag after POST /fapi/v1/marginType.","commonSituations":"Reading observations within seconds of toggling margin type, or a partially propagated account state after a position was converted.","solutions":["Retry after a short delay once the margin-type change propagates","Verify current margin type via GET /fapi/v2/positionRisk and compare","Avoid flipping margin types while the observation loop is running"],"exampleFix":"// before\nawait client.futures_change_margin_type(symbol='BTCUSDT', marginType='CROSSED')\nobs = await connector.read_account_observation()\n\n// after\nawait client.futures_change_margin_type(symbol='BTCUSDT', marginType='CROSSED')\nawait asyncio.sleep(2)\nobs = await connector.read_account_observation()","handlingStrategy":"retry","validationCode":"risk = await client.futures_position_risk()\nfor p in risk:\n    if p['marginType'].lower() == 'cross' and float(p['isolatedMargin']) != 0:\n        raise RuntimeError(f\"{p['symbol']}: cross position still reports isolated margin; wait for propagation\")","typeGuard":null,"tryCatchPattern":"try:\n    obs = await connector.read_account_observation()\nexcept UsdMObservationError as e:\n    if \"zero isolated margin\" in str(e):\n        await asyncio.sleep(2)\n        obs = await connector.read_account_observation()\n    else:\n        raise","preventionTips":["Wait for margin-type change confirmation before observing","Do not flip margin modes while the observation loop runs","Re-verify marginType via positionRisk after changes"],"tags":["binance","futures","cross-margin","invariant"],"backgroundTag":"margin-mode-mismatch","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}