Error Handling
Understanding and handling errors from the PDFGen Studio API.
HTTP Status Codes
| Code | Name | Description |
|---|---|---|
200 | OK | Request successful |
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Invalid or missing API key |
403 | Forbidden | Access denied to resource |
404 | Not Found | Resource not found |
422 | Unprocessable Entity | Validation failed |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error |
503 | Service Unavailable | Temporary unavailability |
Error Response Format
All errors return a consistent JSON structure:
{
"error": "Error Type",
"message": "Human-readable error description",
"statusCode": 400,
"details": ["Optional array of specific issues"]
}
Common Errors
Authentication Errors
Missing API Key
{
"error": "Unauthorized",
"message": "API key is required",
"statusCode": 401
}
Solution: Include the Authorization: Bearer YOUR_API_KEY header.
Invalid API Key
{
"error": "Unauthorized",
"message": "Invalid API key",
"statusCode": 401
}
Solution: Verify your API key is correct and hasn't been revoked.
Revoked API Key
{
"error": "Unauthorized",
"message": "API key has been revoked",
"statusCode": 401
}
Solution: Generate a new API key from your dashboard.
Validation Errors
Missing Required Field
{
"error": "Bad Request",
"message": "HTML content is required",
"statusCode": 400
}
Invalid Option Value
{
"error": "Validation Error",
"message": "Invalid option value",
"statusCode": 422,
"details": [
"format must be one of: pdf, png, jpg",
"quality must be between 1 and 100"
]
}
Invalid JSON
{
"error": "Bad Request",
"message": "Invalid JSON in request body",
"statusCode": 400
}
Resource Errors
Template Not Found
{
"error": "Not Found",
"message": "Template not found",
"statusCode": 404
}
Solution: Verify the template ID exists and you have access to it.
Rendering Errors
Timeout
{
"error": "Timeout",
"message": "Render timeout exceeded",
"statusCode": 422
}
Solution: Increase the timeout option or simplify your content.
Navigation Error (URL Renderer)
{
"error": "Navigation Error",
"message": "Failed to load URL: net::ERR_NAME_NOT_RESOLVED",
"statusCode": 422
}
Solution: Verify the URL is accessible and publicly reachable.
Content Too Large
{
"error": "Payload Too Large",
"message": "Request body exceeds maximum size limit",
"statusCode": 413
}
Solution: Reduce the size of your request, especially base64 images.
Rate Limiting
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Retry after 60 seconds.",
"statusCode": 429
}
Response Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704412800
Retry-After: 60
Solution: Implement exponential backoff or upgrade your plan.
Error Handling Best Practices
JavaScript/TypeScript
async function generatePDF(html: string): Promise<Buffer | null> {
try {
const response = await fetch('https://api.pdfgenstudio.com/api/v1/renderer/html', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.PDFGEN_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ html }),
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
console.error('Authentication failed:', error.message);
throw new Error('Invalid API key');
case 422:
console.error('Validation failed:', error.details);
throw new Error(`Validation error: ${error.message}`);
case 429:
const retryAfter = response.headers.get('Retry-After');
console.warn(`Rate limited. Retry after ${retryAfter} seconds`);
throw new Error('Rate limit exceeded');
default:
throw new Error(error.message || 'Unknown error');
}
}
return Buffer.from(await response.arrayBuffer());
} catch (error) {
console.error('PDF generation failed:', error);
throw error;
}
}
Python
import requests
import time
def generate_pdf(html: str, max_retries: int = 3) -> bytes:
for attempt in range(max_retries):
try:
response = requests.post(
'https://api.pdfgenstudio.com/api/v1/renderer/html',
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json',
},
json={'html': html},
timeout=60,
)
if response.status_code == 200:
return response.content
error = response.json()
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f'Rate limited. Waiting {retry_after} seconds...')
time.sleep(retry_after)
continue
if response.status_code == 401:
raise AuthenticationError(error['message'])
if response.status_code == 422:
raise ValidationError(error['message'], error.get('details'))
raise APIError(error['message'], response.status_code)
except requests.Timeout:
if attempt < max_retries - 1:
time.sleep(2 ** attempt) # Exponential backoff
continue
raise TimeoutError('Request timed out after retries')
raise Exception('Max retries exceeded')
Retry with Exponential Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
await sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500) {
await sleep(Math.pow(2, attempt) * 1000);
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Debugging Tips
Enable Verbose Logging
Log the full request and response for debugging:
const response = await fetch(url, options);
console.log('Status:', response.status);
console.log('Headers:', Object.fromEntries(response.headers));
if (!response.ok) {
console.log('Error:', await response.text());
}
Validate Before Rendering
Use the validate=true query param (JSON renderer) to test document structure:
curl -X POST "https://api.pdfgenstudio.com/api/v1/renderer/json?validate=true" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"document": {"pages": []}}'
Check Rate Limit Status
Monitor rate limit headers in every response:
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
console.log(`Rate limit: ${remaining} remaining, resets at ${new Date(reset * 1000)}`);
Contact Support
If you encounter persistent errors:
- Check the Status Page for service issues
- Include the request ID from the
X-Request-IDheader - Contact support at support@pdfgenstudio.com