{"record":{"id":"1541b075a3d50c51","repo":"nautechsystems/nautilus_trader","slug":"a-backtestnode-is-required-for-the-bars-with-fills","errorCode":null,"errorMessage":"A BacktestNode is required for the bars_with_fills chart","messagePattern":"A BacktestNode is required for the bars_with_fills chart","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/nautilus_trader/analysis/tearsheet.py","lineNumber":500,"sourceCode":"    def generate_fills_report(self) -> pd.DataFrame:\n        return self._node.generate_fills_report(self._run_config_id)\n\n\ndef _create_tearsheet_from_result(\n    result: BacktestResult,\n    node: BacktestNode | None,\n    run_config_id: str | None,\n    currency,\n    output_path: str | None,\n    title: str,\n    config,\n    benchmark_returns: pd.Series | None,\n    benchmark_name: str,\n) -> str | None:\n    resolved_run_config_id = run_config_id or result.run_config_id\n    needs_engine = config is not None and \"bars_with_fills\" in config.chart_names\n    if needs_engine and node is None:\n        raise ValueError(\"A BacktestNode is required for the bars_with_fills chart\")\n    if node is not None and resolved_run_config_id is None:\n        raise ValueError(\"run_config_id is required when a BacktestNode is provided\")\n    if node is not None and resolved_run_config_id is not None:\n        _validate_result_node_state(node, resolved_run_config_id)\n\n    engine_view = (\n        _BacktestNodeEngineView(node, resolved_run_config_id)\n        if node is not None and resolved_run_config_id is not None\n        else None\n    )\n    returns = _result_returns_series(result)\n    run_info = _result_run_info(result)\n    account_info = _result_account_info(result, node, resolved_run_config_id, currency)\n\n    if title == \"NautilusTrader Backtest Results\":\n        run_started = _format_optional_iso8601(result.run_started)\n        title = f\"<b>NautilusTrader</b> v{NAUTILUS_VERSION} - Backtest Results\"\n        title += f\"<br><sub>Run started: {run_started}</sub>\"","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/python/nautilus_trader/analysis/tearsheet.py#L482-L518","documentation":"The Betfair data client's HTTP connect step failed; the message re-wraps the underlying BetfairHttpError from BetfairHttpClient::connect(), which performs interactive (non-certificate) login against the Betfair Identity API. Common causes are rejected credentials (LoginFailed), network/DNS/TLS failures, or a proxy misconfiguration. The abort happens before instruments are loaded, so the data client never reaches the streaming stage.","triggerScenarios":"Starting/connecting the data client with wrong username or password (LoginFailed from Identity API); firewall, corporate proxy, or DNS blocking identitysso.betfair.com:443; container missing CA certificates; Betfair Identity API outage during login.","commonSituations":"Password rotated but BETFAIR_PASSWORD stale; VPN or corporate egress blocking Betfair; Docker image without current CA certs; Betfair maintenance window; system clock skew breaking TLS validation.","solutions":["Verify credentials and app key directly (check BETFAIR_* values, confirm the app key is active)","Test egress with curl to https://identitysso.betfair.com/api/login from the same environment and fix proxy/firewall/CA issues","Retry with exponential backoff - transient failures during Betfair incidents recover","If the underlying error is a login rejection (is_login_failed), fix credentials instead of retrying"],"exampleFix":"// before: first failure is fatal\nself.http_client.connect().await?;\n\n// after: distinguish auth rejection from transient failure\nlet mut backoff = std::time::Duration::from_secs(1);\nloop {\n    match self.http_client.connect().await {\n        Ok(()) => break,\n        Err(e) if e.is_login_failed() => return Err(e.into()),\n        Err(e) if retries_left => {\n            tokio::time::sleep(backoff).await;\n            backoff *= 2;\n        }\n        Err(e) => return Err(e.into()),\n    }\n}","handlingStrategy":"retry","validationCode":"// preflight: confirm egress and credential vars before starting the node\nlet ok = tokio::time::timeout(\n    std::time::Duration::from_secs(5),\n    reqwest::get(\"https://identitysso.betfair.com/api/login\"),\n).await.is_ok();\nanyhow::ensure!(ok, \"no egress to Betfair Identity API\");\nanyhow::ensure!(\n    std::env::var(\"BETFAIR_USERNAME\").is_ok()\n        && std::env::var(\"BETFAIR_PASSWORD\").is_ok()\n        && std::env::var(\"BETFAIR_APP_KEY\").is_ok(),\n    \"credentials not configured\"\n);","typeGuard":null,"tryCatchPattern":"match http_client.connect().await {\n    Err(e) if e.is_login_failed() => {\n        // credentials rejected: fix config/env, do not retry\n    }\n    Err(e) => {\n        // transport/transient: log and retry with exponential backoff\n    }\n    Ok(()) => { /* proceed to instrument load */ }\n}","preventionTips":["Verify credentials and egress before market hours with a direct login test","Allow both REST and websocket egress to Betfair domains in firewalls/proxies","Keep container CA certificates current","Wrap node start in bounded retry with backoff"],"tags":["betfair","network","authentication","http","connection","rust"],"backgroundTag":"connection-failed","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}