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-Afterheader - Throws
RateLimitErrorafter 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
- api.md - Error types, authentication
- configuration.md - Timeout/retry configuration
- patterns.md - Error handling patterns