{"record":{"id":"ed12e9a14e3a14e4","repo":"HKUDS/Vibe-Trading","slug":"binance-usd-m-endpoint-endpoint-resolved-to-un","errorCode":null,"errorMessage":"Binance USD-M endpoint '{endpoint}' resolved to unapproved host or path '{url}'.","messagePattern":"Binance USD-M endpoint '(.+?)' resolved to unapproved host or path '(.+?)'\\.","errorType":"exception","errorClass":"UsdMObservationError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connectors/binance/usdm.py","lineNumber":49,"sourceCode":"    \"\"\"Require exact HTTPS base URLs for the two signed USD-M reads.\"\"\"\n    urls = getattr(exchange, \"urls\", None)\n    api_urls = urls.get(\"api\") if isinstance(urls, Mapping) else None\n    expected_paths = {\n        \"fapiPrivateV2\": \"/fapi/v2\",\n        \"fapiPrivateV3\": \"/fapi/v3\",\n    }\n    for endpoint, expected_path in expected_paths.items():\n        url = str(api_urls.get(endpoint, \"\")) if isinstance(api_urls, Mapping) else \"\"\n        parsed = urlparse(url)\n        if (\n            parsed.scheme != \"https\"\n            or parsed.hostname != \"fapi.binance.com\"\n            or parsed.port is not None\n            or parsed.path.rstrip(\"/\") != expected_path\n            or parsed.query\n            or parsed.fragment\n        ):\n            raise UsdMObservationError(\n                f\"Binance USD-M endpoint '{endpoint}' resolved to unapproved host or path '{url}'.\"\n            )\n\n\ndef read_account_observation(\n    exchange: Any,\n    *,\n    source_profile: str,\n    host: str,\n    now: Callable[[], datetime],\n    absolute_tolerance: float = DEFAULT_OBSERVATION_ABSOLUTE_TOLERANCE,\n) -> dict[str, Any]:\n    \"\"\"Read and normalize one fail-closed, single-asset USD-M observation.\"\"\"\n    if not math.isfinite(absolute_tolerance) or absolute_tolerance < 0:\n        raise UsdMObservationError(\"observation absolute tolerance must be non-negative and finite\")\n\n    def close_enough(left: float, right: float) -> bool:\n        return math.isclose(","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/binance/usdm.py#L31-L67","documentation":"assert_exchange_endpoints validates each resolved USD-M endpoint URL: it must have an https scheme, hostname exactly fapi.binance.com, no port, a path equal (after rstrip('/')) to the expected path, and no query or fragment. Any deviation raises UsdMObservationError, which _exchange re-wraps as BinanceConfigError (error 1201's twin at the source). This is deliberate URL-pinning to block SSRF-style or accidental endpoint drift.","triggerScenarios":"A ccxt client whose fapi endpoint URLs resolve with an http scheme, a different hostname (proxy, testnet domain, regional mirror), an explicit :443 port, a trailing path mismatch, or a ?query/#fragment appended. Triggered whenever _exchange builds a usdm client, i.e. on every public trading call (get_quote, place_order, etc.).","commonSituations":"Injecting custom URLs or proxies into ccxt config; enabling set_sandbox_mode before the assertion so ccxt swaps in testnet URLs; ccxt version change altering the fapi URL map shape so lookups return unexpected values; corporate proxies rewriting URLs.","solutions":["Remove custom url overrides from the ccxt client config so ccxt's stock fapi.binance.com URLs are used","Ensure set_sandbox_mode is not rewriting fapi URLs before the assertion if you intend live usdm","Pin a ccxt version compatible with the endpoint map assert_exchange_endpoints expects","Print ex.urls['api'] (fapi entries) to identify exactly which URL violates the pin, then eliminate that override"],"exampleFix":"# before\nclient_config = {'urls': {'api': {'fapiPublic': 'https://fapi.binance.com/fapi/v1/?x=1'}}}\n\n# after\nclient_config = {}  # use ccxt defaults: https://fapi.binance.com, exact paths, no query","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nfor endpoint, url in resolved_fapi_urls(ex).items():\n    p = urlparse(url)\n    assert p.scheme == 'https' and p.hostname == 'fapi.binance.com'\n    assert p.port is None and not p.query and not p.fragment","typeGuard":"def endpoint_is_pinned(url: str, expected_path: str) -> bool:\n    p = urlparse(url)\n    return (p.scheme == 'https' and p.hostname == 'fapi.binance.com'\n            and p.port is None and p.path.rstrip('/') == expected_path\n            and not p.query and not p.fragment)","tryCatchPattern":"from trading.connectors.binance.usdm import UsdMObservationError\ntry:\n    assert_exchange_endpoints(ex)\nexcept UsdMObservationError as exc:\n    logger.error('endpoint pin failed: %s — inspect ex.urls', exc)\n    raise","preventionTips":["Don't rewrite ccxt URLs; configure proxies via ccxt options","Pin ccxt version","Smoke-test endpoint resolution at deploy time","Treat any endpoint-pin failure as a config bug, not transient"],"tags":["binance","ccxt","url-validation","ssrf-prevention","usdm-futures"],"backgroundTag":"api-endpoint-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}