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.