Files
2026-01-30 03:04:10 +00:00

5.3 KiB

Gotchas & Troubleshooting

Rate Limits & 429 Errors

Actual Limits:

  • 1200 requests / 5 minutes per user/token (global)
  • 200 requests / second per IP address
  • GraphQL: 320 / 5 minutes (cost-based)

SDK Behavior:

  • Auto-retry with exponential backoff (default 2 retries, Go: 10)
  • Respects Retry-After header
  • Throws RateLimitError after exhausting retries

Solution:

// Increase retries for rate-limit-heavy workflows
const client = new Cloudflare({ maxRetries: 5 });

// Add application-level throttling
import pLimit from 'p-limit';
const limit = pLimit(10); // Max 10 concurrent requests

SDK-Specific Issues

Go: Required Field Wrapper

Problem: Go SDK requires cloudflare.F() wrapper for optional fields.

// ❌ WRONG - Won't compile or send field
client.Zones.New(ctx, cloudflare.ZoneNewParams{
    Name: "example.com",
})

// ✅ CORRECT
client.Zones.New(ctx, cloudflare.ZoneNewParams{
    Name: cloudflare.F("example.com"),
    Account: cloudflare.F(cloudflare.ZoneNewParamsAccount{
        ID: cloudflare.F("account-id"),
    }),
})

Why: Distinguishes between zero value, null, and omitted fields.

Python: Async vs Sync Clients

Problem: Using sync client in async context or vice versa.

# ❌ WRONG - Can't await sync client
from cloudflare import Cloudflare
client = Cloudflare()
await client.zones.list()  # TypeError

# ✅ CORRECT - Use AsyncCloudflare
from cloudflare import AsyncCloudflare
client = AsyncCloudflare()
await client.zones.list()

Token Permission Errors (403)

Problem: API returns 403 Forbidden despite valid token.

Cause: Token lacks required permissions (scope).

Scopes Required:

Operation Required Scope
List zones Zone:Read (zone-level or account-level)
Create zone Zone:Edit (account-level)
Edit DNS DNS:Edit (zone-level)
Deploy Worker Workers Script:Edit (account-level)
Read KV Workers KV Storage:Read
Write KV Workers KV Storage:Edit

Solution: Re-create token with correct permissions in Dashboard → My Profile → API Tokens.

Pagination Truncation

Problem: Only getting first 20 results (default page size).

Solution: Use auto-pagination iterators.

// ❌ WRONG - Only first page (20 items)
const page = await client.zones.list();

// ✅ CORRECT - All results
const zones = [];
for await (const zone of client.zones.list()) {
  zones.push(zone);
}

Workers Subrequests

Problem: Rate limit hit faster than expected in Workers.

Cause: Workers subrequests count as separate API calls.

Solution: Use bindings instead of REST API in Workers (see ../bindings/).

// ❌ WRONG - REST API in Workers (counts against rate limit)
const client = new Cloudflare({ apiToken: env.CLOUDFLARE_API_TOKEN });
const zones = await client.zones.list();

// ✅ CORRECT - Use bindings (no rate limit)
// Access via env.MY_BINDING

Authentication Errors (401)

Problem: "Authentication failed" or "Invalid token"

Causes:

  • Token expired
  • Token deleted/revoked
  • Token not set in environment
  • Wrong token format

Solution:

// Verify token is set
if (!process.env.CLOUDFLARE_API_TOKEN) {
  throw new Error('CLOUDFLARE_API_TOKEN not set');
}

// Test token
const user = await client.user.tokens.verify();
console.log('Token valid:', user.status);

Timeout Errors

Problem: Request times out (default 60s).

Cause: Large operations (bulk DNS, zone transfers).

Solution: Increase timeout or split operations.

// Increase timeout
const client = new Cloudflare({
  timeout: 300000, // 5 minutes
});

// Or split operations
const batchSize = 100;
for (let i = 0; i < records.length; i += batchSize) {
  const batch = records.slice(i, i + batchSize);
  await processBatch(batch);
}

Zone Not Found (404)

Problem: Zone ID valid but returns 404.

Causes:

  • Zone not in account associated with token
  • Zone deleted
  • Wrong zone ID format

Solution:

// List all zones to find correct ID
for await (const zone of client.zones.list()) {
  console.log(zone.id, zone.name);
}

Limits Reference

Resource/Limit Value Notes
API rate limit 1200/5min Per user/token
IP rate limit 200/sec Per IP
GraphQL rate limit 320/5min Cost-based
Parallel requests (recommended) < 10 Avoid overwhelming API
Default page size 20 Use auto-pagination
Max page size 50 Some endpoints

Best Practices

Security:

  • Never commit tokens
  • Use minimal permissions
  • Rotate tokens regularly
  • Set token expiration

Performance:

  • Batch operations
  • Use pagination wisely
  • Cache responses
  • Handle rate limits

Code Organization:

// Create reusable client instance
export const cfClient = new Cloudflare({
  apiToken: process.env.CLOUDFLARE_API_TOKEN,
  maxRetries: 5,
});

// Wrap common operations
export async function getZoneDetails(zoneId: string) {
  return await cfClient.zones.get({ zone_id: zoneId });
}

See Also