Debugging PDF Generation Issues: A Developer's Field Guide š
April 15, 2025
Your PDF just rendered as a blank page. Or maybe the layout is completely broken. Or worse - it's failing silently with no error message.
Welcome to the wonderful world of PDF debugging.
We've seen thousands of PDFs generated through reportgen.io, and we've learned something: most PDF issues fall into 5 categories. Fix these, and you'll solve 95% of your problems.
Let's debug.
The 5 Most Common PDF Issues (And How to Fix Them)
1ļøā£ The Blank Page Problem
Symptom: PDF generates successfully, but it's completely blank.
Root Causes:
- External resources aren't loading (CSS, images, fonts)
- JavaScript that's trying to run (spoiler: it won't)
- Rendering timing issues
How to Debug:
Step 1: Check for External Resources
Open your browser DevTools Network tab and load your HTML template. Are there any failed requests?
Common culprits:
<!-- ā These will fail in PDF generation -->
<link rel="stylesheet" href="/styles.css"> <!-- Relative path -->
<img src="logo.png"> <!-- Relative path -->
<script src="app.js"></script> <!-- JavaScript won't execute -->The Fix:
<!-- ā
Use absolute URLs -->
<link rel="stylesheet" href="https://yourdomain.com/styles.css">
<img src="https://yourdomain.com/images/logo.png">
<!-- ā
Inline critical CSS -->
<style>
body { font-family: Arial, sans-serif; }
.header { background: #333; color: white; }
</style>Step 2: Remove All JavaScript
PDFs are static documents. JavaScript doesn't run. Period.
<!-- ā This won't work -->
<script>
document.getElementById('total').innerText = calculateTotal();
</script>
<!-- ā
Calculate on the server, pass as data -->
<h2>Total: ${{total}}</h2>Step 3: Test with Minimal HTML
Strip your template down to basics:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>If this works but your full template doesn't, add sections back one by one until you find the problem.
2ļøā£ The Layout Disaster
Symptom: Content is misaligned, overlapping, or just looks terrible.
Root Causes:
- CSS that works in browsers but breaks in PDF rendering
- Viewport/sizing issues
- Print media queries not applied
How to Debug:
Step 1: Avoid Flexbox and CSS Grid
These modern layout systems are unreliable in PDF rendering. Use tables instead.
<!-- ā Flexbox can break -->
<div style="display: flex; justify-content: space-between;">
<div>Left</div>
<div>Right</div>
</div>
<!-- ā
Use tables for reliable layout -->
<table width="100%">
<tr>
<td>Left</td>
<td align="right">Right</td>
</tr>
</table>Step 2: Set Explicit Dimensions
<!-- ā Vague sizing -->
<div class="container">Content</div>
<!-- ā
Explicit dimensions -->
<div style="width: 800px; max-width: 100%;">Content</div>Step 3: Use Print Media Queries
/* Styles for PDF rendering */
@media print {
body {
margin: 0;
padding: 20px;
}
.no-print {
display: none;
}
.page-break {
page-break-after: always;
}
}Step 4: Test Print Preview in Chrome
Before sending to reportgen.io, test your HTML in Chrome:
- Open your HTML file in Chrome
- Press
Cmd+P(Mac) orCtrl+P(Windows) - Look at the print preview
If it looks broken in Chrome's print preview, it will look broken in your PDF.
3ļøā£ The Font Fiasco
Symptom: Fonts are missing, defaulting to Times New Roman, or characters are rendering incorrectly.
Root Causes:
- Custom fonts not loading
- Font files blocked by CORS
- Missing font formats
How to Debug:
Step 1: Verify Font URLs Are Accessible
Test your font URL directly in a browser:
https://yourdomain.com/fonts/custom-font.woff2
If it returns a 404 or CORS error, your fonts won't load.
Step 2: Embed Fonts Properly
<style>
@font-face {
font-family: 'CustomFont';
src: url('https://yourdomain.com/fonts/custom-font.woff2') format('woff2'),
url('https://yourdomain.com/fonts/custom-font.woff') format('woff');
font-weight: normal;
font-style: normal;
}
body {
font-family: 'CustomFont', Arial, sans-serif; /* Fallback is critical */
}
</style>Step 3: Use Google Fonts (Easiest Option)
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Roboto', sans-serif; }
</style>Step 4: Consider Base64 Embedding for Critical Fonts
For absolutely critical fonts, embed them directly:
<style>
@font-face {
font-family: 'CustomFont';
src: url(data:font/woff2;base64,d09GMgABAAAAAA...) format('woff2');
}
</style>4ļøā£ The Image Problem
Symptom: Images are missing, broken, or rendering at the wrong size.
Root Causes:
- Relative image paths
- CORS blocking image requests
- Unsupported image formats
How to Debug:
Step 1: Always Use Absolute URLs
<!-- ā Won't work -->
<img src="/images/logo.png">
<img src="../assets/chart.jpg">
<!-- ā
Will work -->
<img src="https://yourdomain.com/images/logo.png">Step 2: Set Explicit Dimensions
<!-- ā Can cause sizing issues -->
<img src="https://example.com/image.png">
<!-- ā
Explicit dimensions -->
<img src="https://example.com/image.png" width="300" height="200">Step 3: Use Supported Formats
Stick to: PNG, JPG, GIF, SVG
Step 4: For Dynamic Charts, Use Base64
If you're generating charts server-side:
// Generate chart as base64
const chartBase64 = generateChartAsBase64(data);
// Embed in HTML
const html = `<img src="data:image/png;base64,${chartBase64}">`;5ļøā£ The Silent Failure
Symptom: API returns an error, but you can't figure out why.
Root Causes:
- Malformed template syntax
- Invalid data structure
- API authentication issues
How to Debug:
Step 1: Check the Error Response
reportgen.io returns detailed error messages:
const response = await fetch('https://reportgen.io/api/v1/generate-pdf-sync', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const error = await response.json();
console.error('PDF generation failed:', error);
// Look at error.message for details
}Step 2: Validate Your Template Syntax
Each templating engine has different syntax:
<!-- Handlebars -->
<h1>{{title}}</h1>
<p>{{description}}</p><!-- EJS -->
<h1><%= title %></h1>
<p><%= description %></p>Mixing them will fail. Make sure your engine parameter matches your template syntax.
Step 3: Verify API Key
// Check that your API key is set
console.log('API Key:', process.env.REPORTGEN_API_KEY ? 'Set' : 'Missing');Step 4: Test with Minimal Payload
const minimalPayload = {
html_template: '<h1>Test</h1>',
data: {},
engine: 'raw'
};
// If this works, gradually add complexityAdvanced Debugging Techniques
Technique 1: Local HTML Testing
Save your rendered template as a local HTML file and open it in a browser:
const renderedHTML = renderTemplate(template, data);
fs.writeFileSync('debug.html', renderedHTML);
// Open debug.html in Chrome, inspect for issuesTechnique 2: Capture the Rendered HTML
See exactly what reportgen.io is processing:
const payload = {
html_template: template,
data: data,
engine: 'ejs'
};
// Log the full payload
console.log('Sending to reportgen.io:', JSON.stringify(payload, null, 2));Technique 3: Use the Browser's Print CSS Debugger
Chrome DevTools > More Tools > Rendering > Emulate CSS media type > Print
This shows exactly how your HTML will render as a PDF.
Technique 4: Progressive Enhancement
Start simple, add complexity gradually:
// Step 1: Plain HTML
let html = '<h1>Title</h1>';
// Step 2: Add styles
html = '<style>h1 { color: blue; }</style>' + html;
// Step 3: Add images
html = '<img src="https://example.com/logo.png">' + html;
// Test at each stepThe Ultimate Debugging Checklist
When a PDF breaks, run through this checklist:
- Are all resource URLs absolute? (CSS, images, fonts)
- Does it render correctly in Chrome's print preview?
- Have I removed all JavaScript?
- Are fonts loading correctly?
- Is the template syntax correct for the chosen engine?
- Are image dimensions explicitly set?
- Have I checked the API error response?
- Does a minimal version of the template work?
Common Error Messages (And What They Mean)
"Template rendering failed"
Cause: Syntax error in your template Fix: Validate syntax for your templating engine
"Failed to load resource"
Cause: CSS, font, or image URL is unreachable Fix: Use absolute URLs and verify they're accessible
"Unauthorized"
Cause: Invalid or missing API key
Fix: Check X-API-Key header
"Request timeout"
Cause: Template takes too long to render Fix: Use async endpoint for complex PDFs
Still Stuck?
If you've tried everything and your PDF is still broken:
- Check our documentation: docs.reportgen.io
- Review example templates: docs.reportgen.io/examples
- Contact support: [email protected]
Include:
- Your template code
- Sample data
- Error message (if any)
- What you've already tried
We've debugged thousands of PDFs - we'll figure it out.
Final Thoughts
PDF generation is frustrating when it breaks. But with systematic debugging, you can solve almost any issue.
Remember:
- ā Use absolute URLs for everything
- ā Test in Chrome print preview first
- ā Keep layouts simple (tables > flexbox)
- ā Inline critical CSS
- ā Read error messages carefully
Happy debugging! š
Need a rock-solid PDF generation API? Try reportgen.io - 150 PDFs free per month, no credit card required.