本文目前仅提供英文版本。翻译即将推出。
Your Odoo report fails to generate with this in the log:
ERROR: wkhtmltopdf reported a protocol error
ERROR: report.report_helper: Invalid asset URL or network failure during PDF rendering
Sometimes the variant is "Failed loading page" or "ContentNotFoundError". The HTML preview works, the PDF stage fails. This is wkhtmltopdf's catch-all for "I tried to fetch something while rendering and the request failed." On Odoo 17.0/18.0/19.0, the cause is almost always a misconfigured web.base.url or a network policy blocking egress.
Quick Fix
Set web.base.url to a URL that the Odoo server itself can reach over loopback or internal network:
sudo -u postgres psql -d <db> -c "
UPDATE ir_config_parameter
SET value = 'http://127.0.0.1:8069'
WHERE key = 'web.base.url';
"
For multi-host setups, use the internal DNS name. For a single-host setup, http://127.0.0.1:8069 is the safest. wkhtmltopdf running on the Odoo server fetches assets via this URL, and external/public URLs can fail due to firewalls, certificate trust, or DNS resolution.
Why This Happens
When Odoo generates a PDF, it spawns wkhtmltopdf as a subprocess. wkhtmltopdf gets handed HTML with <img src="https://yoursite.com/web/image/123"> references, then makes HTTP requests to fetch those images. The request originates from the Odoo server itself, not the user's browser. Five common breaks:
web.base.urlis the public URL likehttps://ecosire.com, but the Odoo server cannot resolveecosire.comfrom inside the network (or hits a firewall) — image fetch fails.- TLS certificate not trusted by wkhtmltopdf. It uses the system trust store; private CA certificates are not loaded.
- HTTPS to a port that requires sticky session — wkhtmltopdf does not maintain cookies between requests, so an asset behind authentication fails.
- Image stored as
/web/image/<id>requires login — wkhtmltopdf is unauthenticated. Some assets are public, some are not. - Network egress blocked — production servers behind a strict firewall cannot reach external CDNs (Google Fonts, etc.) referenced in the report's CSS.
Step-by-Step Diagnosis
1. Check current web.base.url.
SELECT key, value FROM ir_config_parameter
WHERE key IN ('web.base.url', 'web.base.url.freeze');
2. Test reachability from the Odoo server itself.
sudo -u odoo curl -v http://127.0.0.1:8069/web/login
sudo -u odoo curl -v https://ecosire.com/web/login
The command must succeed with a 200 (or 303 redirect to login). Failure here is your problem.
3. Test the specific asset URL.
# Find an image url in the report
sudo -u odoo curl -v "http://127.0.0.1:8069/web/image/res.partner/7/image_1024"
If this 401s or 404s, the asset is not reachable for unauthenticated wkhtmltopdf.
4. Run wkhtmltopdf with debug.
wkhtmltopdf --enable-local-file-access --debug-javascript test.html out.pdf
The flag dumps every network attempt and its result.
5. Check web.base.url.freeze. If it is True, no other code path can override the URL. Either freeze it correctly or unfreeze:
UPDATE ir_config_parameter SET value = 'False'
WHERE key = 'web.base.url.freeze';
Permanent Fix
Set web.base.url to an internal URL. For most deployments:
# In a post-install script or migration
env['ir.config_parameter'].sudo().set_param('web.base.url', 'http://127.0.0.1:8069')
env['ir.config_parameter'].sudo().set_param('web.base.url.freeze', 'True')
Freezing prevents accidental rewrites by Odoo's "first request" magic that auto-sets web.base.url to whatever URL the first user hit.
For multi-host with a load balancer, use the internal service name:
env['ir.config_parameter'].sudo().set_param('web.base.url', 'http://odoo-internal.local:8069')
For TLS / certificate issues, install your CA in the system trust store:
sudo cp internal-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
wkhtmltopdf reads the system CA bundle — adding your private CA there makes it trusted.
For images requiring authentication, switch to public access for assets used in reports. Either set the field's record rule to allow unauthenticated read, or store the image in a public-accessible field.
For external CDN dependencies, inline them. Embed fonts as base64 in CSS, embed images as base64 in HTML. The report becomes self-contained and immune to network policy.
import base64
def _get_logo_base64(self):
with open('/opt/odoo/custom/my_module/static/src/img/logo.png', 'rb') as f:
return base64.b64encode(f.read()).decode()
Then in the QWeb:
<img t-attf-src="data:image/png;base64,#{logo_base64}"/>
How to Prevent It
- Set
web.base.urlexplicitly in deploys. A post-install script ensures the value is always correct. Manual configuration drifts. - Test report generation in CI. A test that requests a PDF and asserts a successful response and reasonable byte size catches network-policy regressions when egress rules change.
- No external assets in reports. Every image, font, and stylesheet a report references should be local. Reduces failure modes from many to one.
- Monitor egress changes. When the network team tightens firewall rules, report generation often breaks silently. Subscribe to network change notifications and re-test PDFs after each.
- Use
report.urlfor explicit overrides. For specific reports that need a different base URL (rare), setreport.urlper-report instead of changing the global. Keeps changes scoped. - Enable
--enable-local-file-accesscautiously. It lets wkhtmltopdf read local files viafile://URLs. Useful for inline assets but expands attack surface — restrict to trusted templates only.
Related Errors
- PDF report renders blank page — adjacent failure mode in the same toolchain.
- QWeb template not found at runtime — pre-render failure.
- Report translations missing — content-level report bug.
- Page break not working — layout-level report bug.
Frequently Asked Questions
Why does wkhtmltopdf use HTTP to fetch local assets?
Because wkhtmltopdf was designed as a general HTML-to-PDF tool, not Odoo-specific. It treats <img src=> URLs the same way a browser would: HTTP fetch. Odoo could embed assets as data: URLs but the framework opted for the general path. The fix is to make HTTP fetches reliably succeed.
Should web.base.url be HTTP or HTTPS?
For internal use by wkhtmltopdf, HTTP via loopback (http://127.0.0.1:8069) is fastest and avoids TLS issues entirely. If Odoo is HTTPS-only externally and the loopback is only HTTP, this works because the binding listens on both.
My report worked yesterday and broke today. What changed?
Check three things in this order: (1) Did web.base.url change? Some Odoo flows auto-update it on first login. (2) Did the network policy change? (3) Did wkhtmltopdf get auto-updated by an OS package update? Pinning wkhtmltopdf to 0.12.6.1-3 and web.base.url.freeze to True closes both gaps.
Can I run wkhtmltopdf in Docker for isolation?
Yes, with a sidecar container that exposes a localhost endpoint. The OCA report_qweb_signer and other modules support this pattern. Adds operational complexity but isolates the wkhtmltopdf version from the host OS.
My report fetches an external CDN — should I worry?
Yes. Every external resource is a failure point: DNS, TLS, the CDN itself, your firewall. Inline assets eliminate all four. If you must keep an external dependency (a customer wants a live signature image), at least cache it locally with a long TTL and fall back gracefully on fetch failure.
How do I debug wkhtmltopdf running inside Odoo's subprocess?
Set report.url to your test URL and add --debug-javascript --enable-internal-links to the wkhtmltopdf command line via the paperformat's report_pdf_options (Odoo 17.0+). The flags surface JS errors and link resolution issues in the Odoo log.
What replaces wkhtmltopdf in Odoo's roadmap?
Odoo has experimented with Chromium-based rendering and weasyprint. Neither has replaced wkhtmltopdf as of 19.0 because of compatibility issues with existing templates. The OCA report_qweb_pdf_chromium module offers a chromium alternative if you need modern CSS support — the trade-off is a heavier runtime dependency.
Need help with a tricky Odoo error? ECOSIRE's Odoo experts have shipped 215+ modules — get expert help.
作者
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
相关文章
如何将自定义按钮添加到 Odoo 表单视图 (2026)
将自定义操作按钮添加到 Odoo 19 表单视图:Python 操作方法、视图继承、条件可见性、确认对话框。经过生产测试。
如何在没有 Studio 的情况下在 Odoo 中添加自定义字段 (2026)
通过 Odoo 19 中的自定义模块添加自定义字段:模型继承、视图扩展、计算字段、存储/非存储决策。代码优先,版本控制。
如何使用外部布局在 Odoo 中添加自定义报告
使用 web.external_layout 在 Odoo 19 中构建品牌 PDF 报告:QWeb 模板、paperformat、操作绑定。带有印刷徽标+页脚覆盖。