Data-correctness release. Bulgaria joined the euro on 1 January 2026, and the ECB moved several euro area series to new codes. Three functions kept returning data, so nothing failed, but the data stopped updating.
When Eurostat moved the HICP to the ECOICOP 2 classification, the ECB
published it in a new HICP dataflow (data provider 4D0) and froze the
old ICP dataflow at December 2025. ecb_hicp() therefore reported euro
area inflation of 1.9% (December 2025) as the latest figure when it was
3.8% (September 2026). It now reads the HICP dataflow. Index levels are
on the new base, 2025 = 100.
measure = "monthly_rate" never returned data: the ECB publishes no
month-on-month HICP series in either dataflow, so the request was a 404.
It is now computed from the index, within each country, and is NA across
a gap in the index rather than spanning two months.
ecb_gdp(), ecb_government_debt() and ecb_unemployment() requested
the euro area 20 aggregate (I9), which the ECB stopped extending after
Bulgaria's accession: ecb_gdp() ended at 2026 Q1 while Q2 and Q3 were
published. They now request the current composition (I10), which is
back-calculated over the full history.
The cache never expired: once a series had been downloaded, the same call
returned that copy indefinitely, missing every later release and revision.
Cached responses, and the dataflow list behind list_ecb_dataflows(),
are now re-fetched after 24 hours. Set
options(readecb.cache_ttl = <hours>) to change this.
Live tests check that the euro area HICP and GDP series are recent, so a series that silently stops updating fails the suite rather than passing.
ecb_fetch() aborted with "Invalid query. Check the dataflow and key"
whenever the response body was HTML. That was never the right diagnosis: an
unknown dataflow or series key returns HTTP 404 with
application/problem+json, which is handled separately. HTML means the
request never reached the data service at all, which in practice is the
portal's rate limiter, a gateway timeout, or maintenance.
The effect was that a user whose key was perfectly correct got told to go and check it. The message now distinguishes rate limiting (HTTP 400 with an HTML body, which is how the portal signals it) from a service that is temporarily unavailable, and says in both cases that the key is probably fine.
is_transient only recognised the rate-limit signal. Supplying it replaced
httr2's default, which silently stopped 429 and 5xx from being retried at
all, so a gateway timeout failed on first sight. Those are now retried, and
the total retry wait is capped with max_seconds so a refused host costs
seconds rather than half a minute.
The ECB Data Portal intermittently returns 504s, taking about 30 seconds to
do so. The network tests now skip on exactly the conditions the package
classifies as transient, via a new expect_ecb() helper. A real bug still
fails: this only skips server-side conditions, so the suite stays a useful
signal instead of going red whenever the upstream service has a wobble.
Every \donttest{} example that reaches the ECB Data Portal is wrapped in try().
14 blocks were affected. CRAN runs these in its additional-issues
donttest check, on build machines the upstream host routinely refuses or
rate-limits, and an example that could not reach it was an ERROR rather
than a printed condition. The options(op) cache restore stays outside the
try() so it runs either way.
This is the CRAN Repository Policy requirement that a package using an internet resource fail gracefully when the resource is unavailable. It is the rule obr was archived under on 2026-08-22.
ecb_fetch() now checks for empty API responses and throws an informative
error instead of returning a malformed data frame.ecb_exchange_rate() now validates currency codes upfront, with a helpful
error pointing to list_exchange_rates().ecb_hicp() now validates the country argument is a non-empty character
vector.tempdir() instead of the user's home directory,
fixing CRAN policy compliance for \donttest examples.options(readecb.cache_dir = ...).ecb_policy_rates(), ecb_estr(), ecb_mortgage_rates(), ecb_lending_rates() for ECB interest rate data.ecb_euribor() for EURIBOR interbank lending rates at 1M, 3M, 6M, and 12M tenors.ecb_hicp() for harmonised consumer price inflation.ecb_exchange_rate() and list_exchange_rates() for euro reference exchange rates.ecb_yield_curve() for euro area government bond yields.ecb_money_supply() for M1, M2, M3 monetary aggregates.ecb_gdp() for quarterly euro area real GDP.ecb_unemployment() for the monthly euro area unemployment rate.ecb_government_debt() for the annual government debt-to-GDP ratio.ecb_get() and list_ecb_dataflows() for direct access to any ECB dataflow.clear_cache() to remove locally cached files.