reportgen
Back to all posts

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:

  1. Open your HTML file in Chrome
  2. Press Cmd+P (Mac) or Ctrl+P (Windows)
  3. 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 complexity

Advanced 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 issues

Technique 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 step

The 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:

  1. Check our documentation: docs.reportgen.io
  2. Review example templates: docs.reportgen.io/examples
  3. 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.