Unhandled KeyError: 'dsInfo' in requires_2fa when session cookie is invalidated (HTTP 421)
Overview
When the Apple session cookie has been invalidated, icloudpd crashes with an unhandled KeyError: 'dsInfo' instead of reporting an authentication failure. Exit code is 1 and there is no actionable error message.
Apple returns HTTP 421 from POST https://setup.icloud.com/setup/ws/1/validate with the body:
{"success": false, ..., "error": "Missing X-APPLE-WEBAUTH-TOKEN cookie"}Note that this response does include a trustTokens array and requestInfo, but it has no dsInfo key.
icloudpd logs ERROR Authentication required for Account. (421) and then crashes.
Steps to Reproduce
- Invalidate or remove the session cookie in the
--cookie-directory. - Run any command that authenticates, e.g.:
icloudpd --username <user> --auth-only --cookie-directory <dir> --password-provider console --mfa-provider consoleEnvironment:
- Version
1.32.3, commit sha2035bb1, commit timestampSat May 30 11:20:46 2026 CDT(fromicloudpd --version) - Installed as the PyPI wheel; the pip console script shims into a PyInstaller-frozen bundle at
site-packages/icloudpd/icloudpd - Linux aarch64, Python 3.12, running headless/unattended via a systemd timer
Observed reproducibly on 9 consecutive daily unattended runs, 2026-07-21 through 2026-07-29 — byte-identical failure each time apart from timestamps and the [PYI-<pid>] value.
Expected Behavior
icloudpd reports an authentication failure (a classified auth error / PyiCloud* exception) so the operator knows an interactive re-auth is required.
Actual Behavior
Traceback (most recent call last):
File "starters/icloudpd.py", line 6, in <module>
File "icloudpd/cli.py", line 609, in cli
File "icloudpd/base.py", line 261, in run_with_configs
File "icloudpd/base.py", line 438, in _process_all_users_once
File "icloudpd/base.py", line 902, in core_single_run
File "icloudpd/authentication.py", line 104, in authenticator
File "pyicloud_ipd/base.py", line 642, in requires_2fa
KeyError: 'dsInfo'
[PYI-671579:ERROR] Failed to execute script 'icloudpd' due to unhandled exception!Context
Apparent cause. requires_2fa indexes dsInfo on the validate response unconditionally. On an invalidated/expired session that key is absent, so it raises KeyError rather than surfacing the auth failure. At commit 2035bb1, src/pyicloud_ipd/base.py:
@property
def requires_2sa(self) -> bool:
"""Returns True if two-step authentication is required."""
return self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 634 — defensive
...
@property
def requires_2fa(self) -> bool:
"""Returns True if two-factor authentication is required."""
return (
self.data["dsInfo"].get("hsaVersion", 0) == 2 # line 642 — raises
and (self.data.get("hsaChallengeRequired", False) or not self.is_trusted_session)
and self.data["dsInfo"].get("hasICloudQualifyingDevice", False)
)The adjacent requires_2sa already handles a missing dsInfo via .get("dsInfo", {}); requires_2fa does not.
Impact for unattended use. Because the failure is a crash rather than a classified auth error, log-based failure classification cannot distinguish it from an arbitrary error, so automated pipelines cannot tell the operator that an interactive re-auth is required.
Suggested fix. In requires_2fa, handle a missing dsInfo (e.g. .get("dsInfo", {}), matching requires_2sa) and raise the appropriate authentication exception so callers see an auth failure rather than a KeyError.
Source: icloud-photos-downloader/icloud_photos_downloader