{"record":{"id":"94c948d3938e2d73","repo":"HKUDS/Vibe-Trading","slug":"configured-profile-is-paper-but-the-resolved-host","errorCode":null,"errorMessage":"Configured profile is paper, but the resolved host '{host}' is not the testnet host '{expected}'.","messagePattern":"Configured profile is paper, but the resolved host '(.+?)' is not the testnet host '(.+?)'\\.","errorType":"exception","errorClass":"BinanceConfigError","httpStatus":null,"severity":"critical","filePath":"agent/src/trading/connectors/binance/sdk.py","lineNumber":757,"sourceCode":"        try:\n            assert_exchange_endpoints(ex)\n        except UsdMObservationError as exc:\n            raise BinanceConfigError(str(exc)) from None\n    return ex\n\n\ndef _assert_host(cfg: BinanceConfig) -> None:\n    \"\"\"Fail closed when the resolved host does not match the declared environment.\n\n    The host is the authoritative discriminator: testnet keys cannot reach the\n    live host. A live profile must resolve to ``api.binance.com``; a paper\n    profile must resolve to the configured testnet host.\n    \"\"\"\n    host = (urlparse(cfg.host).hostname or cfg.host or \"\").lower()\n    if cfg.is_testnet:\n        expected = (urlparse(cfg.testnet_host).hostname or cfg.testnet_host or \"\").lower()\n        if host != expected:\n            raise BinanceConfigError(\n                f\"Configured profile is paper, but the resolved host '{host}' is not the testnet host '{expected}'.\"\n            )\n        return\n    expected_url = USDM_LIVE_HOST if cfg.market_type == \"usdm\" else LIVE_HOST\n    expected = urlparse(expected_url).hostname or expected_url\n    if host != expected:\n        raise BinanceConfigError(\n            f\"Configured profile is live, but the resolved host '{host}' is not the live host '{expected}'.\"\n        )\n\n\ndef _missing_fields(cfg: BinanceConfig) -> list[str]:\n    missing = []\n    if not cfg.api_key:\n        missing.append(\"api_key\")\n    if not cfg.api_secret:\n        missing.append(\"api_secret\")\n    return missing","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/binance/sdk.py#L739-L775","documentation":"_assert_host fail-closes when the config declares paper/testnet (cfg.is_testnet) but the parsed hostname of cfg.host does not equal the parsed hostname of cfg.testnet_host. It prevents a testnet-labeled profile from silently hitting any other host (including live). Raised before any network call in check_status, get_account_snapshot, get_positions, get_open_orders, get_quote, and get_historical_bars.","triggerScenarios":"cfg.is_testnet=True with cfg.host pointing at the live host, a placeholder, localhost, an empty string, or a differently-spelled testnet hostname (e.g. 'testnet.binancefuture.com' vs the configured testnet_host value). Also when cfg.host contains a scheme/port that changes the parsed hostname.","commonSituations":"Env var for host set for live while profile env says paper; copy-pasted config where host and testnet_host disagree; testnet host constant changed across library versions leaving stale configs; trailing path or port in host string altering urlparse().hostname.","solutions":["Set cfg.host (or the env feeding it) to exactly the testnet_host value the config declares","Compare urlparse(host).hostname and urlparse(testnet_host).hostname in a config sanity check at startup","Upgrade/pin the library so testnet_host constant matches the current Binance testnet domain","Audit environment precedence: the paper profile must resolve host from the testnet setting, not from a live-host override"],"exampleFix":"# before\ncfg = BinanceConfig(host=\"https://fapi.binance.com\", is_testnet=True, testnet_host=\"https://testnet.binancefuture.com\")\n\n# after\ncfg = BinanceConfig(host=cfg.testnet_host, is_testnet=True, testnet_host=\"https://testnet.binancefuture.com\")","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nhost = (urlparse(cfg.host).hostname or '').lower()\nexpected = (urlparse(cfg.testnet_host).hostname or '').lower()\nif cfg.is_testnet and host != expected:\n    raise SystemExit(f'paper profile must use {expected}, got {host}')","typeGuard":"def is_paper_host_consistent(cfg) -> bool:\n    return not cfg.is_testnet or (urlparse(cfg.host).hostname or '').lower() == (urlparse(cfg.testnet_host).hostname or '').lower()","tryCatchPattern":"try:\n    sdk.check_status(cfg)\nexcept BinanceConfigError as exc:\n    if 'not the testnet host' in str(exc):\n        cfg = replace(cfg, host=cfg.testnet_host)\n        sdk.check_status(cfg)\n    else:\n        raise","preventionTips":["Derive host from the profile: paper => testnet_host, live => canonical live host","Single-source the host env var; audit overrides at startup","Add config lint that asserts hostname equality for paper profiles"],"tags":["binance","config-validation","testnet","host-mismatch","fail-closed"],"backgroundTag":"environment-host-mismatch","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}