Skip to content

Commit 7fee7ee

Browse files
cyberjunkyclaude
andcommitted
feat: detect CAPTCHA_REQUIRED in mobile and portal login handlers
Plain-requests login paths (no TLS impersonation) get fingerprinted by Cloudflare and receive a CAPTCHA_REQUIRED response. Previously this was swallowed into the generic "login failed: {raw dict}" message. Now it raises a clear GarminConnectConnectionError that falls through to the next strategy, with a readable log line instead of a dict dump. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent dce19b2 commit 7fee7ee

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

garminconnect/client.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,12 @@ def _do_mobile_login(self, sess: Any, email: str, password: str) -> None:
434434
if res.get("error", {}).get("status-code") == "429":
435435
raise GarminConnectTooManyRequestsError("Mobile login: 429 in JSON body")
436436

437+
if resp_type == "CAPTCHA_REQUIRED":
438+
raise GarminConnectConnectionError(
439+
"Mobile login: CAPTCHA required (bot challenge) — "
440+
"falling through to next strategy"
441+
)
442+
437443
raise GarminConnectConnectionError(f"Mobile login failed: {res}")
438444

439445
# ------------------------------------------------------------------ #
@@ -761,6 +767,12 @@ def _do_portal_web_login(self, sess: Any, email: str, password: str) -> None:
761767
if res.get("error", {}).get("status-code") == "429":
762768
raise GarminConnectTooManyRequestsError("Portal login: 429 in JSON body")
763769

770+
if resp_type == "CAPTCHA_REQUIRED":
771+
raise GarminConnectConnectionError(
772+
"Portal login: CAPTCHA required (bot challenge) — "
773+
"falling through to next strategy"
774+
)
775+
764776
raise GarminConnectConnectionError(f"Portal web login failed: {res}")
765777

766778
# ------------------------------------------------------------------ #

0 commit comments

Comments
 (0)