Skip to content

fix(nodes): retry Gmail rate-limit 403s instead of failing fast (#1560)#1571

Open
meetp06 wants to merge 1 commit into
rocketride-org:developfrom
meetp06:fix/gh-1560-gmail-403-rate-limit-retry
Open

fix(nodes): retry Gmail rate-limit 403s instead of failing fast (#1560)#1571
meetp06 wants to merge 1 commit into
rocketride-org:developfrom
meetp06:fix/gh-1560-gmail-403-rate-limit-retry

Conversation

@meetp06

@meetp06 meetp06 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Addresses #1560 (the 403 rate-limit retry item — see Scope).

Problem

gmail_client.execute() retries transient 429/5xx statuses but fails fast on every 403. Gmail returns rate-limit/quota conditions as 403 with a structured reason (userRateLimitExceeded, rateLimitExceeded, quotaExceeded) — those are transient and retryable, but currently surface as a hard error mid-run.

Fix

  • Add _is_rate_limit_403(exc) which parses the structured error body (error.status / error.errors[].reason) and returns True only for rate-limit/quota reasons. Any parse failure conservatively returns False (non-retryable).
  • Include such 403s in the execute() retry path alongside the existing transient statuses. Scope/permission 403s still fail fast with the reconnect message.

Tests

  • _is_rate_limit_403: detects all three rate-limit reasons; rejects a scope reason, non-JSON, and empty body.
  • execute(): a rate-limit 403 is retried and then succeeds; a scope 403 fails immediately with no retry.
  • _time.sleep is patched so the backoff doesn't slow the suite.

Verification (run locally)

python -m pytest nodes/test/tool_gmail/test_gmail.py  →  90 passed
ruff check   →  All checks passed
ruff format  →  already formatted

Scope

This is the 403 rate-limit retry item of #1560. The credential-hardening items (token_uri validation, broker-refresh reliability, schemeless broker URL) are handled in #1569; the protobuf floor bump and the nodes/core/ client hoist remain as separate follow-up.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved Gmail request handling for temporary rate limits and quota-related errors.
    • Retryable 403 responses are now retried automatically, while authorization and permission errors fail immediately with a clear message.
    • Added coverage for retry behavior, error classification, and malformed responses.

…etride-org#1560)

gmail_client.execute() retried 429/5xx but failed fast on every 403, including
transient rate-limit/quota 403s that Gmail returns
(userRateLimitExceeded / rateLimitExceeded / quotaExceeded). Those are
retryable and should not surface as a hard error.

Add `_is_rate_limit_403()` which inspects the structured error body
(error.status / error.errors[].reason) and treats only rate-limit/quota
reasons as retryable, and include such 403s in the execute() retry path
alongside the existing transient statuses. Scope/permission 403s still fail
fast with the reconnect message. Any parse failure conservatively treats the
403 as non-retryable.

Tests: reason detection (all three rate-limit reasons + scope/garbage
rejection), a rate-limit 403 retried then succeeding, and a scope 403 failing
without retry. Full tool_gmail suite passes (90 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added the module:nodes Python pipeline nodes label Jul 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor
🤖 Internal: Discord sync marker

Auto-managed by the Discord notification workflow. Stores the linked Discord message ID and forum thread ID. Do not edit or delete.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4180e2e8-fcfe-4925-9fde-1500a5df06aa

📥 Commits

Reviewing files that changed from the base of the PR and between cbe5d12 and c5b2708.

📒 Files selected for processing (2)
  • nodes/src/nodes/tool_gmail/gmail_client.py
  • nodes/test/tool_gmail/test_gmail.py

📝 Walkthrough

Walkthrough

Gmail request retries now recognize structured 403 rate-limit and quota errors while preserving immediate failure for permission and scope errors. Unit tests cover response parsing, retry-to-success behavior, and fail-fast handling.

Changes

Gmail retry handling

Layer / File(s) Summary
Structured 403 rate-limit detection
nodes/src/nodes/tool_gmail/gmail_client.py, nodes/test/tool_gmail/test_gmail.py
Adds JSON-based detection for retryable Gmail quota and rate-limit reasons, with tests for valid, invalid, and permission-related responses.
Execute retry integration
nodes/src/nodes/tool_gmail/gmail_client.py, nodes/test/tool_gmail/test_gmail.py
Retries qualifying 403 responses alongside existing retry statuses, while scope and permission failures raise ValueError without retrying.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: jmaionchi, rod-christensen, stepmikhaylov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: Gmail 403 rate-limit errors are now retried instead of failing fast.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

module:nodes Python pipeline nodes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant