← Back to Blog
Operations by Featured

Report Generation Issues in Odoo: A Troubleshooting Checklist

Report Generation Issues in Odoo: A Troubleshooting Checklist

A user clicks “Print” and Odoo just sits there. Or the PDF comes back, but it looks weird: no colors, no logo, text running off the page. Worse case: it’s corrupted.

Report generation in Odoo touches more moving parts than most people expect: workers, wkhtmltopdf binary, python libs… Here is a checklist you can go through when you face an issue with them.

A first advice: start by checking the HTML report in the browser

Every report has an HTML preview at the /report/html/<report_name>/<record_ids> route. If the styling is already broken there, the problem is in your QWeb template or asset bundle, not in wkhtmltopdf, and you should stop looking at the PDF pipeline entirely.

Odoo hangs or times out when generating a report?

If clicking “Print” makes the whole interface freeze, or the request just never comes back, check the number of workers in the Odoo config file before anything else.

[options]
workers = 4

workers must be set to 4 or more for report generation to work reliably. Odoo delegates PDF rendering to a separate process, and with too few workers that process can end up starving the main request loop, or waiting on a worker slot that never frees up. This is a known, documented issue: odoo/odoo#199880.

PDF renders but the styling is missing?

The content is there: right data, right layout, but no colors, no custom fonts, no background images. This almost always means wkhtmltopdf rendered the report without being able to load the CSS and image assets it needed.

Report rendered with broken CSS

Check the report.url system parameter. Go to Settings → Technical → System Parameters and look for report.url.

wkhtmltopdf does not receive a self-contained HTML blob — the HTML Odoo passes it contains references back to Odoo itself for all the CSS and assets it needs. A typical report body starts like this:

<base href="http://instance-name:8069?debug=0"/>
<link type="text/css" rel="stylesheet" href="/web/assets/2194678-b048873/web.report_assets_pdf.min.css" data-asset-bundle="web.report_assets_pdf" data-asset-version="b048873"/>
<link type="text/css" rel="stylesheet" href="/web/assets/2196817-cf6127f/web.report_assets_common.min.css" data-asset-bundle="web.report_assets_common" data-asset-version="cf6127f"/>

The <base href> is set to report.url. wkhtmltopdf resolves every relative asset URL against it, then fetches those assets from the Odoo server over HTTP. If report.url points to an address wkhtmltopdf cannot reach, it will render the page without loading any of those stylesheets, which is why the output looks unstyled.

Assets load too late: only the last pages are unstyled

On large multi-document reports — think printing more than 5 delivery slips at once — you can see a pattern where the first pages render correctly but the last ones are missing the logo or background. The cause is timing: wkhtmltopdf uses a WebKit engine that runs JavaScript to load assets, and it has a built-in delay before it considers the page “ready” to print. The default (200 ms) is not enough when the document is large and asset fetching is slow.

Since Odoo 14.0 (odoo/odoo#114503), Odoo passes --javascript-delay to wkhtmltopdf and reads its value from the report.print_delay system parameter, defaulting to 1000 ms. If you hit this pattern, go to Settings → Technical → System Parameters and increase report.print_delay (value in milliseconds). Start with 2000 or 3000 and check whether the last pages come back styled.

Big reports crash?

wkhtmltopdf report error

If a specific report crashes wkhtmltopdf, especially a long one with a lot of pages or a heavy table, look at the wkhtmltopdf version before touching anything else.

wkhtmltopdf --version

Check it against Odoo’s official wkhtmltopdf recommendations, which track which build is validated against which Odoo version. wkhtmltopdf has a long history of version-specific regressions on large documents, and the fix is often just picking a different patch version, not changing anything in your code.

We have hit this more than once:

  • wkhtmltopdf 0.12.2.1 on Odoo 8 is known to enlarge and overlap fonts, fixed by downgrading to 0.12.1.
  • on an old Odoo 9.0 instance, a large report triggered a Segmentation fault with wkhtmltopdf 0.12.4. Downgrading to 0.12.3 fixed it, with no other change.
  • 0.12.4 on Odoo 13 has dropped headers and footers for some users, fixed by upgrading to 0.12.5.
  • More recently, on an Odoo 18.0 instance, a large report crashed on 0.12.6.1-3 but ran fine on 0.12.5-2.

There is no single “correct” version that works for every report on every OS. If you hit a crash on a big report, treat the wkhtmltopdf version as a variable to test, not a constant, and keep a known-good version pinned in your deployment once you find one.

Crash with error code -11 or -9? Check resource limits before the binary itself

Not every crash on a large report is a version bug. Two error codes point somewhere else entirely:

  • Error code -11 (segmentation fault) with a message like “Memory limit too low or maximum file number of subprocess reached” means wkhtmltopdf itself ran out of RAM, or hit an open-file-descriptor limit, while rendering. Check ulimit -n for the Odoo user, and check available memory on the host during report generation, not just at idle.
  • Error code -9 means the process was killed, usually by Odoo’s own worker limits, limit_time_real or the memory soft/hard limits in the config file. A report that used to work and now gets killed after a data volume increase is a limits problem, not a wkhtmltopdf regression: raise the relevant limit rather than chasing a version change.

Fonts render wrong, or not at all

If the PDF shows a fallback font, enlarged or overlapping text, or a custom font that looks fine in /report/html but not in the PDF, the cause is almost always that wkhtmltopdf cannot see the font, not that the font is broken:

  • wkhtmltopdf renders with the fonts installed on the host, not the ones in the browser making the request. A custom font needs its package installed on the machine that runs wkhtmltopdf, which is easy to forget when that machine is a separate report worker or container from the one you use to test in a browser.
  • The font also needs to be pulled in through an asset bundle such as web.report_assets_common. A font that is only referenced from a stylesheet outside that bundle is invisible to wkhtmltopdf even if it is installed on the server and renders fine in the browser.
  • Non-Latin locales sometimes need their own locale-specific font package installed server-side; this shows up as boxes or missing characters only for particular languages.

Tierce modules impact

Check whether the OCA module report_wkhtmltopdf_param is installed and whether it carries custom values. This module lets you pass extra command-line flags to wkhtmltopdf, and one flag in particular shows up often in troubleshooting: --disable-smart-shrinking. It changes how wkhtmltopdf scales content to fit the page, and a value set for one report can have side effects on others if it was applied instance-wide.

Also check for other modules that customize the native odoo report generation code paths: _render_qweb_pdf, _run_wkhtmltopdf, _render_qweb_pdf_prepare_streams. You might have some suprises: we faced a case that generated corrupted PDFs with Python <=3.10 (account_invoice_en16931).

Check the PDF python dependencies

Odoo relies on PyPDF2 (or more recently PyPDF on Python ≥ 3.13) for PDF manipulation, including merging multiple reports into a single file and handling existing PDF attachments. If reports that combine multiple documents fail while single-document reports work fine, check that lib:

pip freeze | grep -i pdf

Use the barcode widget, not the barcode route

If your report includes barcodes, avoid generating them via the /report/barcode/... route with a plain <img> tag:

<!-- avoid this -->
<img t-att-src="'/report/barcode/Code128/%s' % o.code"/>

When wkhtmltopdf encounters these <img> tags, it makes one HTTP request back to the Odoo server per barcode to fetch the image. On a report with many barcodes this can flood the server with concurrent requests and cause wkhtmltopdf to crash or time out.

Use the QWeb barcode widget instead, which embeds the barcode as inline base64 data — no extra HTTP request at all:

<div t-field="o.code" t-options="{'widget': 'barcode', 'width': 600, 'height': 100}"/>

Odoo’s own modules were updated to do this in odoo/odoo#64211. If you have custom reports that still use the route, migrating them to the widget typically fixes unexplained crashes on barcode-heavy documents.

Ready to get the most out of Odoo?

Whether you are starting a new implementation, upgrading from an older version, or optimizing your current setup — our Odoo-first team is here to help.