Skip to content

Map QUOTA_EXCEEDED to TooManyRequestsError - #2264

Open
Diaoul wants to merge 1 commit into
iMicknl:mainfrom
Diaoul:fix/map-quota-exceeded-to-rate-limit
Open

Diaoul wants to merge 1 commit into
iMicknl:mainfrom
Diaoul:fix/map-quota-exceeded-to-rate-limit

Conversation

@Diaoul

@Diaoul Diaoul commented Sep 27, 2026 •

Copy link
Copy Markdown

Fixes #2263

🐛 Problem

  • The cloud reports its polling quota as errorCode: QUOTA_EXCEEDED, message "Too many requests, try again later".
  • That code is in none of the three error maps, so check_response falls through to raise OverkizError(result).
  • TooManyRequestsError was reachable only via ("AUTHENTICATION_ERROR", "Too many requests", ...) — the login path, not polling.
  • Callers therefore cannot tell rate limiting from an unknown server error without matching on the payload text.

✅ Fix

One entry, among the codes that are already their own sole discriminator:

("QUOTA_EXCEEDED", None, TooManyRequestsError),
  • Keyed off the errorCode, not the message. The code is the API's machine-readable contract; the message is prose that can be reworded, recased or localised without the API changing.
  • Deliberately not in _MESSAGE_FALLBACK_MAP — that map exists "for responses where the errorCode alone is not enough or may vary across API versions", and QUOTA_EXCEEDED is unambiguous on its own.
  • _ERROR_CODE_MESSAGE_MAP is consulted first and the existing ("AUTHENTICATION_ERROR", "Too many requests", …) login entry is untouched, so nothing that resolves today changes — this only types responses that were falling through.

Behaviour, verified against check_response:

payload before after
QUOTA_EXCEEDED + "Too many requests, try again later" ❌ bare OverkizError ✅
QUOTA_EXCEEDED + any other message ❌ ✅
QUOTA_EXCEEDED + no error field ❌ ✅
AUTHENTICATION_ERROR + "Too many requests" (login) ✅ ✅
AUTHENTICATION_ERROR + "Bad credentials" BadCredentialsError unchanged

📊 Why it matters

Measured on an Atlantic Cozytouch V2 hub (cloud API) via Home Assistant's overkiz integration, eight commands issued in parallel to eight heaters:

observed
fetch_events rate during the burst 1.32 /s (endpoint documents 1/s)
polling intervals under 1 s 5, shortest 0.23 s
QUOTA_EXCEEDED raised 1
commands that reached the hub 5 / 8
worst state-delivery lag 28.97 s

Because the error arrived untyped, the consumer's back-off — which keys on TooManyRequestsError — never ran. It kept polling at the interval that hit the limit, surfaced a full traceback as an unexpected error, and the failed update marked every entity unavailable, after which Home Assistant refused the remaining three service calls outright.

🧪 Tests

Two fixtures added, both wired into the existing check_response parametrisation in tests/test_client.py:

  • quota-exceeded.json — the payload as the cloud sends it
  • quota-exceeded-other-message.json — same code, different prose, so the assertion pins the code path rather than the wording

645 passed, 2 skipped; mypy clean; ruff check and ruff format --check clean on both touched files.

The 3 pre-existing ruff check findings and 5 unformatted files on main are untouched.

@Diaoul
Diaoul force-pushed the fix/map-quota-exceeded-to-rate-limit branch from 922d8d4 to ad4f06c Compare September 27, 2026 22:04
The cloud reports its polling quota as errorCode QUOTA_EXCEEDED with the
message "Too many requests, try again later". That code appears in none of the
three error maps, so check_response falls through to the generic
`raise OverkizError(result)` and callers cannot tell rate limiting from an
unknown server error without matching on the payload text.

TooManyRequestsError was reachable only for AUTHENTICATION_ERROR carrying the
same message, which is the login path, not polling.

Key off the errorCode rather than the message: the code is the API's
machine-readable contract, while the message is prose that can be reworded,
recased or localised without the API changing. QUOTA_EXCEEDED is unambiguous on
its own, so it belongs with the other sole-discriminator codes rather than in
the message fallback map, which exists for codes that vary.

Fixes iMicknl#2263

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Diaoul
Diaoul force-pushed the fix/map-quota-exceeded-to-rate-limit branch from ad4f06c to 96efaef Compare September 27, 2026 22:19
@@ -0,0 +1,4 @@
{
"errorCode": "QUOTA_EXCEEDED",
"error": "Quota exceeded"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly for demonstration purposes, I did not observe that in real conditions with my integration. The message always was Too many requests, try again later.

Let me know if I should remove this "fake" test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

QUOTA_EXCEEDED is not mapped to TooManyRequestsError, so rate limiting arrives untyped

1 participant