在 session cookie 失效时,requires_2fa 中出现未处理的 KeyError: 'dsInfo'(HTTP 421)
作者: artushin创建于 2026年7月29日更新于 2026年7月29日
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
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 635 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 636 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 637 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 638 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 639 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 640 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 641 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 642 — raises
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 643 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 644 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 645 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 646 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 647 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 648 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 649 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 650 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 651 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 652 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 653 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 654 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 655 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 656 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 657 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 658 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 659 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 660 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 661 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 662 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 663 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 664 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 665 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 666 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 667 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 668 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 669 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 670 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 671 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 672 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 673 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 674 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 675 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 676 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 677 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 678 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 679 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 680 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 681 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 682 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 683 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 684 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 685 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 686 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 687 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 688 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 689 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 690 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 691 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 692 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 693 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 694 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 695 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 696 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 697 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 698 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 699 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 700 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 701 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 702 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 703 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 704 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 705 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 706 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 707 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 708 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 709 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 710 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 711 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 712 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 713 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 714 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 715 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 716 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 717 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 718 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 719 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 720 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 721 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 722 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 723 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 724 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 725 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 726 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 727 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 728 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 729 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 730 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 731 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 732 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 733 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line 734 — defensive
self.data.get("dsInfo", {}).get("hsaVersion", 0) >= 1 and ( # line内容来源: icloud-photos-downloader/icloud_photos_downloader