Streamlit Cloud: DNS resolution failure when calling PVGIS (pvlib.iotools.get_pvgis_hourly)

Hi everyone,

my Streamlit app (https://pv-dc-electrolysis.streamlit.app/) started failing on Streamlit Cloud when fetching PVGIS data via pvlib.iotools.get_pvgis_hourly. The request dies before connecting with a DNS error for re.jrc.ec.europa.eu. The same code works fine locally and used to work on Cloud until recently.

Here is the full error:


───────────────────── Traceback (most recent call last) ───────────────────────

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connection.py:198

in _new_conn

195 │ │ :return: New socket connection.

196 │ │ """

197 │ │ try:

❱ 198 │ │ │ sock = connection.create_connection(

199 │ │ │ │ (self._dns_host, self.port),

200 │ │ │ │ self.timeout,

201 │ │ │ │ source_address=self.source_address,

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/util/connection.py

:60 in create_connection

57 │ except UnicodeError:

58 │ │ raise LocationParseError(f"'{host}', label empty or too long")

59 │

❱ 60 │ for res in socket.getaddrinfo(host, port, family, socket.SOCK_STRE

61 │ │ af, socktype, proto, canonname, sa = res

62 │ │ sock = None

63 │ │ try:

/usr/local/lib/python3.13/socket.py:977 in getaddrinfo

974 │ # We override this function since we want to translate the numeric

975 │ # and socket type values to enum constants.

976 │ addrlist = []

❱ 977 │ for res in _socket.getaddrinfo(host, port, family, type, proto, fl

978 │ │ af, socktype, proto, canonname, sa = res

979 │ │ addrlist.append((_intenum_converter(af, AddressFamily),

980 │ │ │ │ │ │ _intenum_converter(socktype, SocketKind),

────────────────────────────────────────────────────────────────────────────────

gaierror: [Errno -5] No address associated with hostname

The above exception was the direct cause of the following exception:

────────────────────── Traceback (most recent call last) ───────────────────────

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connectionpool.py:

787 in urlopen

784 │ │ │ response_conn = conn if not release_conn else None

785 │ │ │

786 │ │ │ # Make the request on the HTTPConnection object

❱ 787 │ │ │ response = self._make_request(

788 │ │ │ │ conn,

789 │ │ │ │ method,

790 │ │ │ │ url,

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connectionpool.py:

488 in _make_request

485 │ │ │ │ new_e, (OSError, NewConnectionError, TimeoutError, SS

486 │ │ │ ) and (conn and conn.proxy and not conn.has_connected_to_

487 │ │ │ │ new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)

❱ 488 │ │ │ raise new_e

489 │ │

490 │ │ # conn.request() calls http.client.*.request, not the method

491 │ │ # urllib3.request. It also calls makefile (recv) on the socke

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connectionpool.py:

464 in _make_request

461 │ │ try:

462 │ │ │ # Trigger any extra validation we need to do.

463 │ │ │ try:

❱ 464 │ │ │ │ self._validate_conn(conn)

465 │ │ │ except (SocketTimeout, BaseSSLError) as e:

466 │ │ │ │ self._raise_timeout(err=e, url=url, timeout_value=con

467 │ │ │ │ raise

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connectionpool.py:

1093 in _validate_conn

1090 │ │

1091 │ │ # Force connect early to allow us to validate the connection.

1092 │ │ if conn.is_closed:

❱ 1093 │ │ │ conn.connect()

1094 │ │

1095 │ │ # TODO revise this, see https://github.com/urllib3/urllib3/is

1096 │ │ if not conn.is_verified and not conn.proxy_is_verified:

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connection.py:753

in connect

750 │ │

751 │ │ try:

752 │ │ │ sock: socket.socket | ssl.SSLSocket

❱ 753 │ │ │ self.sock = sock = self._new_conn()

754 │ │ │ server_hostname: str = self.host

755 │ │ │ tls_in_tls = False

756

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connection.py:205

in _new_conn

202 │ │ │ │ socket_options=self.socket_options,

203 │ │ │ )

204 │ │ except socket.gaierror as e:

❱ 205 │ │ │ raise NameResolutionError(self.host, self, e) from e

206 │ │ except SocketTimeout as e:

207 │ │ │ raise ConnectTimeoutError(

208 │ │ │ │ self,

────────────────────────────────────────────────────────────────────────────────

NameResolutionError: <urllib3.connection.HTTPSConnection object at

0x7d622def0c20>: Failed to resolve 're.jrc.ec.europa.eu' ([Errno -5] No address

associated with hostname)

The above exception was the direct cause of the following exception:

────────────────────── Traceback (most recent call last) ───────────────────────

/home/adminuser/venv/lib/python3.13/site-packages/requests/adapters.py:644

in send

641 │ │ │ timeout = TimeoutSauce(connect=timeout, read=timeout)

642 │ │

643 │ │ try:

❱ 644 │ │ │ resp = conn.urlopen(

645 │ │ │ │ method=request.method,

646 │ │ │ │ url=url,

647 │ │ │ │ body=request.body,

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/connectionpool.py:

841 in urlopen

838 │ │ │ elif isinstance(new_e, (OSError, HTTPException)):

839 │ │ │ │ new_e = ProtocolError("Connection aborted.", new_e)

840 │ │ │

❱ 841 │ │ │ retries = retries.increment(

842 │ │ │ │ method, url, error=new_e, _pool=self, _stacktrace=sys

843 │ │ │ )

844 │ │ │ retries.sleep()

/home/adminuser/venv/lib/python3.13/site-packages/urllib3/util/retry.py:519

in increment

516 │ │

517 │ │ if new_retry.is_exhausted():

518 │ │ │ reason = error or ResponseError(cause)

❱ 519 │ │ │ raise MaxRetryError(_pool, url, reason) from reason # typ

520 │ │

521 │ │ log.debug("Incremented Retry for (url='%s'): %r", url, new_ret

522

────────────────────────────────────────────────────────────────────────────────

MaxRetryError: HTTPSConnectionPool(host='re.jrc.ec.europa.eu', port=443): Max

retries exceeded with url:

/api/v5_3/seriescalc?lat=37.3891&lon=-5.9845&outputformat=json&angle=0.0&aspect=

0.0&pvcalculation=0&pvtechchoice=crystSi&mountingplace=free&trackingtype=0&compo

nents=1&usehorizon=1&optimalangles=0&optimalinclination=0&loss=0&startyear=2023&

endyear=2023 (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection

object at 0x7d622def0c20>: Failed to resolve 're.jrc.ec.europa.eu' ([Errno -5]

No address associated with hostname)"))

During handling of the above exception, another exception occurred:

────────────────────── Traceback (most recent call last) ───────────────────────

/home/adminuser/venv/lib/python3.13/site-packages/streamlit/runtime/scriptru

nner/exec_code.py:128 in exec_func_with_error_handling

/home/adminuser/venv/lib/python3.13/site-packages/streamlit/runtime/scriptru

nner/script_runner.py:669 in code_to_exec

/mount/src/pv-array---dc-direct-coupling---electrolyzer-array/app.py:322 in

<module>

319

320 # Fetch (cached unless site/year/tilt/azimuth change)

321 with st.spinner("Fetching PVGIS data and computing effective irradian

❱ 322 │ data, meta, E_eff_base = fetch_pvgis_and_effective_irradiance(

323 │ │ SITE_LAT, SITE_LON, SITE_ALT, SITE_TZ, year, SURFACE_TILT, SU

324 │ )

325

/home/adminuser/venv/lib/python3.13/site-packages/streamlit/runtime/caching/

cache_utils.py:227 in __call__

/home/adminuser/venv/lib/python3.13/site-packages/streamlit/runtime/caching/

cache_utils.py:269 in _get_or_create_cached_value

/home/adminuser/venv/lib/python3.13/site-packages/streamlit/runtime/caching/

cache_utils.py:328 in _handle_cache_miss

/mount/src/pv-array---dc-direct-coupling---electrolyzer-array/app.py:295 in

fetch_pvgis_and_effective_irradiance

292 │ SITE_LAT = SITE_LAT_local; SITE_LON = SITE_LON_local; SITE_ALT =

293 │ SURFACE_TILT = SURFACE_TILT_local; SURFACE_AZIMUTH = SURFACE_AZIM

294 │

❱ 295 │ data, meta = iotools.get_pvgis_hourly(

296 │ │ latitude=SITE_LAT, longitude=SITE_LON,

297 │ │ surface_tilt=SURFACE_TILT, surface_azimuth=SURFACE_AZIMUTH,

298 │ │ start=START, end=END,

/home/adminuser/venv/lib/python3.13/site-packages/pvlib/iotools/pvgis.py:231

in get_pvgis_hourly

228 │ │ params['peakpower'] = peakpower

229 │

230 │ # The url endpoint for hourly radiation is 'seriescalc'

❱ 231 │ res = requests.get(url + 'seriescalc', params=params, timeout=time

232 │ # PVGIS returns really well formatted error messages in JSON for H

233 │ # 400 BAD REQUEST so try to return that if possible, otherwise rai

234 │ # HTTP/1.1 error caught by requests

/home/adminuser/venv/lib/python3.13/site-packages/requests/api.py:73 in get

70 │ :rtype: requests.Response

71 │ """

72 │

❱ 73 │ return request("get", url, params=params, **kwargs)

74

75

76 def options(url, **kwargs):

/home/adminuser/venv/lib/python3.13/site-packages/requests/api.py:59 in

request

56 │ # avoid leaving sockets open which can trigger a ResourceWarning i

57 │ # cases, and look like a memory leak in others.

58 │ with sessions.Session() as session:

❱ 59 │ │ return session.request(method=method, url=url, **kwargs)

60

61

62 def get(url, params=None, **kwargs):

/home/adminuser/venv/lib/python3.13/site-packages/requests/sessions.py:589

in request

586 │ │ │ "allow_redirects": allow_redirects,

587 │ │ }

588 │ │ send_kwargs.update(settings)

❱ 589 │ │ resp = self.send(prep, **send_kwargs)

590 │ │

591 │ │ return resp

592

/home/adminuser/venv/lib/python3.13/site-packages/requests/sessions.py:703

in send

700 │ │ start = preferred_clock()

701 │ │

702 │ │ # Send the request

❱ 703 │ │ r = adapter.send(request, **kwargs)

704 │ │

705 │ │ # Total elapsed time of the request (approximately)

706 │ │ elapsed = preferred_clock() - start

/home/adminuser/venv/lib/python3.13/site-packages/requests/adapters.py:677

in send

674 │ │ │ │ # This branch is for urllib3 v1.22 and later.

675 │ │ │ │ raise SSLError(e, request=request)

676 │ │ │

❱ 677 │ │ │ raise ConnectionError(e, request=request)

678 │ │

679 │ │ except ClosedPoolError as e:

680 │ │ │ raise ConnectionError(e, request=request)

────────────────────────────────────────────────────────────────────────────────

ConnectionError: HTTPSConnectionPool(host='re.jrc.ec.europa.eu', port=443): Max

retries exceeded with url:

/api/v5_3/seriescalc?lat=37.3891&lon=-5.9845&outputformat=json&angle=0.0&aspect=

0.0&pvcalculation=0&pvtechchoice=crystSi&mountingplace=free&trackingtype=0&compo

nents=1&usehorizon=1&optimalangles=0&optimalinclination=0&loss=0&startyear=2023&

endyear=2023 (Caused by NameResolutionError("<urllib3.connection.HTTPSConnection

object at 0x7d622def0c20>: Failed to resolve 're.jrc.ec.europa.eu' ([Errno -5]

No address associated with hostname)"))

Here is the link to the GitHub repository: GitHub - TobiasFranzBRB/PV-array---DC-direct-coupling---Electrolyzer-array

Environment

  • Streamlit Cloud

  • Python 3.13

  • pvlib + requests

  • Endpoint: https://re.jrc.ec.europa.eu/api/v5_3/seriescalc

Observations

  • Works locally (no DNS issues).

  • Recently began failing on Streamlit Cloud only.

  • Looks like an outbound DNS/egress issue (failure occurs during hostname resolution, before TLS connect).

Many thanks in advance!

Your deployed app seems to work for me.