Error Medic

Troubleshooting Notion API Rate Limits (HTTP 429) and 502 Bad Gateway Errors

Fix Notion API 429 Too Many Requests and 502 Bad Gateway errors by implementing exponential backoff, request batching, and optimizing payload sizes.

Last updated:
Last verified:
1,159 words
Key Takeaways
  • Exceeding the Notion API hard limit of 3 requests per second triggers HTTP 429 Too Many Requests.
  • Complex queries, large payload sizes, or upstream server timeouts often result in intermittent HTTP 502 Bad Gateway errors.
  • Quick fix: Implement exponential backoff with jitter, parse the Retry-After header, and paginate or batch your requests.
Fix Approaches Compared
MethodWhen to UseTimeRisk
Exponential BackoffHandling standard HTTP 429 rate limits15 minsLow
Payload & Query OptimizationResolving HTTP 502 Bad Gateway timeouts1 hourMedium
Request BatchingBulk data ingestion or mass updates2 hoursMedium

Understanding Notion API Errors: HTTP 429 and HTTP 502

When integrating with the Notion API, developers frequently encounter two disruptive errors: HTTP 429 Too Many Requests (Rate Limiting) and HTTP 502 Bad Gateway. While they manifest differently, they are often symptoms of the same underlying issue: sending too much data or too many requests too quickly for Notion's infrastructure to process.

The Anatomy of a Notion API Rate Limit (HTTP 429)

The Notion API enforces a strict rate limit of 3 requests per second (RPS) per integration. If your application exceeds this threshold, Notion will reject subsequent requests and return an HTTP 429 status code. The response body typically contains an error object detailing the rate limit violation, and crucially, the HTTP headers will include a Retry-After header. This header specifies the number of seconds your application must wait before making another request.

Failing to respect this header and continuing to hammer the API will not only result in sustained 429 errors but can also lead to temporary blocklisting of your integration token.

The Mystery of the HTTP 502 Bad Gateway

Unlike the clear-cut 429 error, an HTTP 502 Bad Gateway error from the Notion API is often more perplexing. A 502 indicates that one server on the internet received an invalid response from another server. In the context of the Notion API, this usually means that Notion's edge routing layer (like Cloudflare or AWS API Gateway) timed out waiting for Notion's core backend database to process your request.

This typically happens in three scenarios:

  1. Unoptimized Database Queries: Querying a massive Notion database without sufficient filters or relying on complex rollup/formula calculations that take too long to resolve.
  2. Oversized Payloads: Attempting to append dozens of heavily nested blocks (like deeply nested lists or large table structures) in a single PATCH request.
  3. Platform Degradation: Occasional internal hiccups on Notion's end during peak usage hours.

Step 1: Diagnose the Root Cause

Before implementing a fix, you must determine whether you are hitting a hard rate limit or causing upstream timeouts. Check your application logs for the exact HTTP status codes and response bodies.

For HTTP 429: Look at the response headers. If you see Retry-After, you are definitively hitting the 3 RPS limit.

HTTP/1.1 429 Too Many Requests
Retry-After: 5
Content-Type: application/json

{
  "object": "error",
  "status": 429,
  "code": "rate_limited",
  "message": "Rate limited. Please try again later."
}

For HTTP 502: The response body is usually HTML generated by a load balancer, not a structured JSON error from Notion. If your application logs show 502s immediately following large batch operations or complex queries, payload size is your primary suspect.

Step 2: Implement Exponential Backoff for 429 Errors

The most robust way to handle Notion API rate limits is to implement an HTTP client that automatically intercepts 429 responses, reads the Retry-After header, pauses execution, and retries the request. If the Retry-After header is missing, you should fall back to a standard exponential backoff algorithm with jitter.

Jitter (adding a small random delay) is critical if you have multiple worker threads hitting the Notion API simultaneously; without it, all workers will wake up at the exact same time and immediately trigger another 429.

Step 3: Optimize Payloads for 502 Errors

If you are encountering 502 Bad Gateway errors, retrying immediately will often result in another 502. Instead, you need to reduce the computational burden on Notion's servers:

  1. Reduce Page Size: When querying databases, lower the page_size parameter from the default (100) to 50 or 25.
  2. Chunk Block Appends: If you are appending 100 blocks to a page, split the operation into four sequential requests of 25 blocks each.
  3. Simplify Filters: Move complex filtering logic to your application layer. Query a broader dataset and filter it in memory rather than forcing Notion's backend to evaluate complex nested AND/OR conditions on large databases.

By combining robust retry logic with optimized payload management, you can build a highly resilient Notion integration that gracefully handles both rate limits and upstream timeouts.

Frequently Asked Questions

python
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import time

class NotionRetry(Retry):
    """
    Custom Retry class that prioritizes the Retry-After header
    specific to Notion's API behavior.
    """
    def get_retry_after(self, response):
        # Check for Notion's specific Retry-After header
        retry_after = response.headers.get("Retry-After")
        if retry_after:
            return float(retry_after)
        return super().get_retry_after(response)

def get_notion_client(token):
    session = requests.Session()
    
    # Configure Retry strategy: 
    # Retries on 429 (Too Many Requests), 502 (Bad Gateway), 503, and 504.
    # Uses exponential backoff if Retry-After is missing.
    retries = NotionRetry(
        total=5,
        backoff_factor=1, # 1, 2, 4, 8, 16 seconds...
        status_forcelist=[429, 500, 502, 503, 504],
        allowed_methods=["HEAD", "GET", "PUT", "POST", "PATCH", "DELETE"]
    )
    
    adapter = HTTPAdapter(max_retries=retries)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    
    session.headers.update({
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
        "Content-Type": "application/json"
    })
    
    return session

# Example Usage:
# client = get_notion_client("secret_your_notion_token")
# response = client.get("https://api.notion.com/v1/users")
# print(response.json())
E

Error Medic Editorial

A collective of Senior Site Reliability Engineers and DevOps practitioners dedicated to solving complex integration, infrastructure, and API reliability issues.

Sources

Related Guides