From fdf1180722a225671fc91f789893896bfee1053c Mon Sep 17 00:00:00 2001 From: Steve Dudenhoeffer Date: Fri, 23 Jan 2026 02:36:41 -0500 Subject: [PATCH] Add better error handling for Cloudflare rate limiting - Handle None returns from pull_statuses gracefully - Add specific error messages for rate limiting scenarios - Skip None posts in iteration to avoid TypeErrors Co-Authored-By: Claude Opus 4.5 --- src/poller.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/poller.py b/src/poller.py index bf74367..11c4db2 100644 --- a/src/poller.py +++ b/src/poller.py @@ -98,15 +98,38 @@ def fetch_and_relay_post(post_url: str) -> bool: api = Api() # Fetch user's statuses and find the matching post print(f"Fetching statuses for @{username} to find post {post_id}...") - statuses = list(api.pull_statuses(username, replies=True)) + statuses_gen = api.pull_statuses(username, replies=True) + + if statuses_gen is None: + print( + "Failed to fetch statuses (API returned None). " + "This may be due to rate limiting or Cloudflare blocking.", + file=sys.stderr, + ) + return False + + statuses = list(statuses_gen) + + if not statuses: + print( + "No statuses returned. The API may be rate-limited or blocked.", + file=sys.stderr, + ) + return False for post in statuses: - if str(post.get("id", "")) == post_id: + if post and str(post.get("id", "")) == post_id: print(f"Found post {post_id}") return process_single_post(post, username) print(f"Post not found in recent statuses: {post_id}", file=sys.stderr) return False + except TypeError as e: + print( + f"API error (likely rate-limited or blocked by Cloudflare): {e}", + file=sys.stderr, + ) + return False except Exception as e: print(f"Error fetching post: {e}", file=sys.stderr) return False @@ -129,10 +152,21 @@ def poll_loop() -> None: print(f"Checking for new posts from @{TRUTH_USER}...") # Fetch recent statuses - statuses = list(api.pull_statuses(TRUTH_USER, replies=False)) + statuses_gen = api.pull_statuses(TRUTH_USER, replies=False) + if statuses_gen is None: + print( + "Failed to fetch statuses (rate-limited or blocked). Retrying...", + file=sys.stderr, + ) + time.sleep(POLL_INTERVAL) + continue + + statuses = list(statuses_gen) # Process in chronological order (oldest first) for post in reversed(statuses): + if post is None: + continue post_id = str(post.get("id", "")) if not post_id: continue @@ -175,9 +209,18 @@ def initial_seed() -> None: api = Api() try: - statuses = list(api.pull_statuses(TRUTH_USER, replies=False)) + statuses_gen = api.pull_statuses(TRUTH_USER, replies=False) + if statuses_gen is None: + print( + "Failed to fetch statuses (rate-limited or blocked).", file=sys.stderr + ) + return + + statuses = list(statuses_gen) count = 0 for post in statuses: + if post is None: + continue post_id = str(post.get("id", "")) if post_id and not is_post_seen(post_id): mark_post_seen(post_id)