{"record":{"id":"c0d8ae803f44dc14","repo":"OpenBB-finance/OpenBB","slug":"failed-to-fetch-data-from-ecb-status-code-re","errorCode":null,"errorMessage":"Failed to fetch data from ECB. -> Status Code: {response.status_code}","messagePattern":"Failed to fetch data from ECB\\. -> Status Code: (.+?)","errorType":"http","errorClass":"OpenBBError","httpStatus":null,"severity":"error","filePath":"openbb_platform/providers/ecb/openbb_ecb/models/currency_reference_rates.py","lineNumber":52,"sourceCode":"        \"\"\"Transform query.\"\"\"\n        return ECBCurrencyReferenceRatesQueryParams(**params)\n\n    @staticmethod\n    def extract_data(\n        query: ECBCurrencyReferenceRatesQueryParams,\n        credentials: dict[str, str] | None,\n        **kwargs: Any,\n    ) -> dict:\n        \"\"\"Extract the raw data from the ECB website.\"\"\"\n        # pylint: disable=import-outside-toplevel\n        import xmltodict\n        from openbb_core.provider.utils.helpers import make_request\n\n        results = {}\n        url = \"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml\"\n        response = make_request(url)\n        if response.status_code != 200:\n            raise OpenBBError(\n                \"Failed to fetch data from ECB.\"\n                + f\" -> Status Code: {response.status_code}\"\n            )\n        data = xmltodict.parse(response.content)\n        rates_data = data[\"gesmes:Envelope\"][\"Cube\"][\"Cube\"][\"Cube\"]\n        rates = {d[\"@currency\"]: d[\"@rate\"] for d in rates_data}\n        results[\"date\"] = data[\"gesmes:Envelope\"][\"Cube\"][\"Cube\"][\"@time\"]\n        results[\"EUR\"] = 1\n        results.update(rates)\n\n        return results\n\n    @staticmethod\n    def transform_data(\n        query: ECBCurrencyReferenceRatesQueryParams, data: dict, **kwargs: Any\n    ) -> ECBCurrencyReferenceRatesData:\n        \"\"\"Transform data.\"\"\"\n        return ECBCurrencyReferenceRatesData.model_validate(data)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/providers/ecb/openbb_ecb/models/currency_reference_rates.py#L34-L70","documentation":"Raised by the ECB currency-reference-rates fetcher when GET https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml returns any status other than 200. The daily XML is the sole source for this endpoint, so a non-200 means the feed itself was unreachable, blocked, or moved.","triggerScenarios":"Calling obb.currency.reference_rates(provider=\"ecb\") while ecb.europa.eu returns 403 (bot-blocking/rate-limiting from cloud egress IPs), 5xx during ECB site maintenance, or a proxy/firewall in the environment returning 407/502.","commonSituations":"CI runners and containers whose shared IPs get throttled by the ECB WAF; corporate proxies that intercept the request; transient ECB outages; running bulk jobs that refresh the daily rates many times per hour.","solutions":["Retry after a short backoff — 403/5xx from ECB is often transient rate-limiting.","Cache the daily file yourself: it changes once per day (~16:00 CET), so fetch at most daily instead of per-request.","Check https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml in a browser/curl from the same machine to confirm reachability and the actual status code.","If behind a proxy, set HTTPS_PROXY env var so make_request goes through it; if blocked, switch provider or mirror the XML."],"exampleFix":"# before\nrates = obb.currency.reference_rates(provider=\"ecb\")\n\n# after\nimport time\nfrom openbb_core.provider.utils.errors import OpenBBError\nfor attempt in range(3):\n    try:\n        rates = obb.currency.reference_rates(provider=\"ecb\")\n        break\n    except OpenBBError as e:\n        if \"Status Code\" in str(e) and attempt < 2:\n            time.sleep(2 ** attempt)\n            continue\n        raise","handlingStrategy":"retry","validationCode":"import requests\n\ndef ecb_fx_feed_reachable() -> bool:\n    return requests.get(\"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml\", timeout=10).status_code == 200","typeGuard":null,"tryCatchPattern":"import time\nfrom openbb_core.provider.utils.errors import OpenBBError\nfor attempt in range(4):\n    try:\n        rates = obb.currency.reference_rates(provider=\"ecb\")\n        break\n    except OpenBBError as e:\n        if \"Status Code\" in str(e) and attempt < 3:\n            time.sleep(2 ** attempt)\n            continue\n        raise","preventionTips":["Fetch the daily FX XML at most once per day and cache it yourself.","Add exponential backoff for 403/5xx from ecb.europa.eu.","Configure proxy env vars in corporate networks so requests aren't intercepted."],"tags":["ecb","fx","http-status","network","rate-limit"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}