Skip to main content

Error Handling

Understanding and handling errors from the PDFGen Studio API.

HTTP Status Codes

CodeNameDescription
200OKRequest successful
400Bad RequestInvalid request parameters
401UnauthorizedInvalid or missing API key
403ForbiddenAccess denied to resource
404Not FoundResource not found
422Unprocessable EntityValidation failed
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error
503Service UnavailableTemporary 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.

{
"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:

  1. Check the Status Page for service issues
  2. Include the request ID from the X-Request-ID header
  3. Contact support at support@pdfgenstudio.com