From 6b9cac318bd8aef8a0e5c7851dc447772f81dc09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B8rn?= Date: Mon, 14 Sep 2026 14:03:36 +0200 Subject: [PATCH 1/2] Fix some issues in error handling --- CHANGELOG.md | 4 ++++ pyproject.toml | 2 +- src/cradl/response.py | 9 ++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37e5cab..640ce94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 0.6.7 - 2026-09-14 + +- Fix `decode_response` matching `TooManyRequestsException`/`LimitExceededException`/`InvalidCredentialsException` against the `message` field using substring matching instead of exact equality against `response.json().values()`. This was silently broken whenever the API wrapped the message (e.g. `"[Forbidden] Too Many Requests"`), causing a plain `requests.exceptions.HTTPError` to be raised instead, which bypassed the `TooManyRequestsException` retry/backoff in `Client._make_request`. + ## Version 0.6.3 - 2026-03-03 - Bugfix for Kinde claims check diff --git a/pyproject.toml b/pyproject.toml index 3734827..89421a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cradl" -version = "0.6.3" +version = "0.6.7" description = "Python SDK for Cradl" authors = [{ name = "Cradl", email = "hello@cradl.ai" }] readme = "README.md" diff --git a/src/cradl/response.py b/src/cradl/response.py index 3f7095f..0d19232 100644 --- a/src/cradl/response.py +++ b/src/cradl/response.py @@ -22,22 +22,21 @@ def decode_response(response, return_json=True): raise e except Exception as e: logger.error('Status code {} body:\n{}'.format(response.status_code, response.text)) + message = response.json().get('message', response.text) if response.status_code == 400: - message = response.json().get('message', response.text) raise BadRequest(message) - if response.status_code == 403 and 'Forbidden' in response.json().values(): + if response.status_code == 403 and 'Forbidden' in message: raise InvalidCredentialsException('Credentials provided are not valid.') if response.status_code == 404: - message = response.json().get('message', response.text) raise NotFound(message) - if response.status_code == 429 and 'Too Many Requests' in response.json().values(): + if response.status_code == 429 and 'Too Many Requests' in message: raise TooManyRequestsException('You have reached the limit of requests per second.') - if response.status_code == 429 and 'Limit Exceeded' in response.json().values(): + if response.status_code == 429 and 'Limit Exceeded' in message: raise LimitExceededException('You have reached the limit of total requests per month.') raise e From 230fd8c1e8a92a1698fe816915aeaf71252580a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B8rn?= Date: Mon, 14 Sep 2026 14:10:12 +0200 Subject: [PATCH 2/2] Deverbosify CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f721e..bf26360 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Version 0.6.7 - 2026-09-14 -- Fix `decode_response` matching `TooManyRequestsException`/`LimitExceededException`/`InvalidCredentialsException` against the `message` field using substring matching instead of exact equality against `response.json().values()`. This was silently broken whenever the API wrapped the message (e.g. `"[Forbidden] Too Many Requests"`), causing a plain `requests.exceptions.HTTPError` to be raised instead, which bypassed the `TooManyRequestsException` retry/backoff in `Client._make_request`. +- Fix error handling for TooManyRequests and Forbidden errors ## Version 0.6.6 - 2026-04-22