HKUDS/Vibe-Trading · error · UsdMObservationError

Binance USD-M endpoint '{endpoint}' resolved to unapproved h

Error message

Binance USD-M endpoint '{endpoint}' resolved to unapproved host or path '{url}'.

What it means

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.

Source

Thrown at agent/src/trading/connectors/binance/usdm.py:49

    """Require exact HTTPS base URLs for the two signed USD-M reads."""
    urls = getattr(exchange, "urls", None)
    api_urls = urls.get("api") if isinstance(urls, Mapping) else None
    expected_paths = {
        "fapiPrivateV2": "/fapi/v2",
        "fapiPrivateV3": "/fapi/v3",
    }
    for endpoint, expected_path in expected_paths.items():
        url = str(api_urls.get(endpoint, "")) if isinstance(api_urls, Mapping) else ""
        parsed = urlparse(url)
        if (
            parsed.scheme != "https"
            or parsed.hostname != "fapi.binance.com"
            or parsed.port is not None
            or parsed.path.rstrip("/") != expected_path
            or parsed.query
            or parsed.fragment
        ):
            raise UsdMObservationError(
                f"Binance USD-M endpoint '{endpoint}' resolved to unapproved host or path '{url}'."
            )


def read_account_observation(
    exchange: Any,
    *,
    source_profile: str,
    host: str,
    now: Callable[[], datetime],
    absolute_tolerance: float = DEFAULT_OBSERVATION_ABSOLUTE_TOLERANCE,
) -> dict[str, Any]:
    """Read and normalize one fail-closed, single-asset USD-M observation."""
    if not math.isfinite(absolute_tolerance) or absolute_tolerance < 0:
        raise UsdMObservationError("observation absolute tolerance must be non-negative and finite")

    def close_enough(left: float, right: float) -> bool:
        return math.isclose(

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Remove custom url overrides from the ccxt client config so ccxt's stock fapi.binance.com URLs are used
  2. Ensure set_sandbox_mode is not rewriting fapi URLs before the assertion if you intend live usdm
  3. Pin a ccxt version compatible with the endpoint map assert_exchange_endpoints expects
  4. Print ex.urls['api'] (fapi entries) to identify exactly which URL violates the pin, then eliminate that override

Example fix

# before
client_config = {'urls': {'api': {'fapiPublic': 'https://fapi.binance.com/fapi/v1/?x=1'}}}

# after
client_config = {}  # use ccxt defaults: https://fapi.binance.com, exact paths, no query
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse
for endpoint, url in resolved_fapi_urls(ex).items():
    p = urlparse(url)
    assert p.scheme == 'https' and p.hostname == 'fapi.binance.com'
    assert p.port is None and not p.query and not p.fragment

Type guard

def endpoint_is_pinned(url: str, expected_path: str) -> bool:
    p = urlparse(url)
    return (p.scheme == 'https' and p.hostname == 'fapi.binance.com'
            and p.port is None and p.path.rstrip('/') == expected_path
            and not p.query and not p.fragment)

Try / catch

from trading.connectors.binance.usdm import UsdMObservationError
try:
    assert_exchange_endpoints(ex)
except UsdMObservationError as exc:
    logger.error('endpoint pin failed: %s — inspect ex.urls', exc)
    raise

Prevention

When it happens

Trigger: 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.).

Common situations: 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.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/ed12e9a14e3a14e4. Report an issue: GitHub.