From e959a7892898ef9fa79716e53824b5166a0bbccc Mon Sep 17 00:00:00 2001 From: RapidPoseidon Date: Fri, 24 Apr 2026 09:00:40 +0000 Subject: [PATCH] fix(client): don't KeyError when a proxy is configured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_get_session_defaults` built `client_kwargs` with only `verify` and `limits`, then inside the `if self.configuration.proxy` branch called `client_kwargs.pop("headers")` — which always raised `KeyError: 'headers'` because the key had never been inserted. Any user behind a corporate proxy was hard-bricked on the first call. Switch to `client_kwargs.get("headers") or {}` and only set the merged dict when there are proxy_headers to merge. `proxy` itself was fine; the only broken path was the headers merge. Also mirrored into `openapi/templates/rest.mustache`. Session: https://session-bc38cc85.poseidon.rapidata.internal/ Co-Authored-By: Claude Opus 4.7 Co-Authored-By: lino --- openapi/templates/rest.mustache | 10 ++++++---- src/rapidata/api_client/rest.py | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/openapi/templates/rest.mustache b/openapi/templates/rest.mustache index 17a85a1d9..9e2fbb865 100644 --- a/openapi/templates/rest.mustache +++ b/openapi/templates/rest.mustache @@ -266,11 +266,13 @@ class RESTClientObject: if self.configuration.proxy: client_kwargs["proxy"] = self.configuration.proxy - existing_headers = client_kwargs.pop("headers") if self.configuration.proxy_headers: - for key, value in self.configuration.proxy_headers.items(): - existing_headers[key] = value - client_kwargs["headers"] = existing_headers + # httpx doesn't have a dedicated `proxy_headers` kwarg the way + # urllib3 does — merging them into the default request headers + # is the closest equivalent. + existing_headers = dict(client_kwargs.get("headers") or {}) + existing_headers.update(self.configuration.proxy_headers) + client_kwargs["headers"] = existing_headers if self.configuration.retries is not None: transport = httpx.HTTPTransport(retries=self.configuration.retries, limits=limits) diff --git a/src/rapidata/api_client/rest.py b/src/rapidata/api_client/rest.py index 0e2bcee85..f14e5e476 100644 --- a/src/rapidata/api_client/rest.py +++ b/src/rapidata/api_client/rest.py @@ -276,11 +276,13 @@ def _get_session_defaults(self): if self.configuration.proxy: client_kwargs["proxy"] = self.configuration.proxy - existing_headers = client_kwargs.pop("headers") if self.configuration.proxy_headers: - for key, value in self.configuration.proxy_headers.items(): - existing_headers[key] = value - client_kwargs["headers"] = existing_headers + # httpx doesn't have a dedicated `proxy_headers` kwarg the way + # urllib3 does — merging them into the default request headers + # is the closest equivalent. + existing_headers = dict(client_kwargs.get("headers") or {}) + existing_headers.update(self.configuration.proxy_headers) + client_kwargs["headers"] = existing_headers if self.configuration.retries is not None: transport = httpx.HTTPTransport(retries=self.configuration.retries, limits=limits)