PDF backends: Chromium counts as usable when only the playwright package is installed, and every render then fails unexplained #514
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#514
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading the PDF backends and every caller that catches their refusal, and rendering throughChromiumBackendwith theplaywrightpackage installed and no browser downloaded.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The report's draft PDF is now atapplications/views.py:1220-1225;documents/pdf.py,documents/views.py, the twoslow.pymodules,core/errands.py:148andcore/server_views.py:92-98have not moved.ChromiumBackend.is_available()asks only whether theplaywrightpackage imports, not whether a Chromium binary is there to launch. The two are separate install steps (CHROMIUM_HINTnames both), so an operator who did the first and not the second gets a backend thatautochooses, that Server settings reports as the one in use, and that fails on every render with an exception nothing turns into the clear messagepdf.py's docstring promises ("a backend that cannot be used produces a clear message rather than an error").documents/pdf.py:184-185(ChromiumBackend.is_available),documents/pdf.py:187-196(ChromiumBackend.session, which launches with noexcept),documents/pdf.py:264-267(get_pdf_backend, theautoloop); the callers that catch onlyPDFBackendUnavailable:documents/views.py:127-131(DraftMixin.draft),applications/views.py:1180-1185(the report's draft PDF),documents/slow.py:41-44anddocuments/slow.py:96-108(the two errands),applications/slow.py:40-47.uv sync --extra chromiumbut notplaywright install chromium.WeasyPrintBackend.is_available()is false,ChromiumBackend.is_available()is true, soautoreturns Chromium.playwright.chromium.launch()then raisesplaywright._impl._errors.Error("Executable doesn't exist at …"), a plainExceptionsubclass. Checked in the snapshot withPLAYWRIGHT_BROWSERS_PATHpointing at an empty folder:is_available()returnedTrueandrender()raised that error, notPDFBackendUnavailable. As a result Download draft PDF on a CV or letter, and the report's draft PDF, answer 500; Export PDF and Record what you sent end with "Something went wrong. The server log has the details." (core/errands.py:148); and Server settings nameschromiumas the working backend (core/server_views.py:92-98).ChromiumBackend.session(), catch Playwright'sErroraroundplaywright.chromium.launch()and raisePDFBackendUnavailablecarryingCHROMIUM_HINTfrom it;render()without a session goes throughsession(), so that one place covers every caller. In addition, makeis_available()check thatplaywright.chromium.executable_pathexists (insidesync_playwright(), or by the same lookup Playwright uses), so thatautofalls through to the "No PDF backend is usable" message and Server settings says none is usable.Done when
tests/test_documents.pythat stubssync_playwrightso thatchromium.launch()raises Playwright'sErrorasserts thatChromiumBackend().render(...)raisesPDFBackendUnavailablewhose message contains theplaywright install chromiumhint, and thatDraftMixin.draftredirects with that message rather than answering 500.