Errors & warnings
A render ends in one of three ways: a PDF with no warnings, a PDF with warnings, or an exception. Warnings mean the renderer skipped something and carried on. Exceptions mean there is no PDF.
#Warnings
The renderer reports anything it had to skip, and the gem collects those messages in Soli::PDF.last_warnings:
pdf = Soli::PDF.render(template: template, data: data)
Soli::PDF.last_warnings
# => ["unresolved placeholder: ${invoice.po_number}",
# "no font covers some glyphs in \"Café Ωmega\""]
| Warning starts with | Cause | Fix |
|---|---|---|
unresolved placeholder: ${…} | The data has no value at that path. The placeholder renders empty. | Check the spelling, or send the key with an empty string. |
no font covers some glyphs in "…" | A character is missing from every loaded font, so it is dropped. | Add a font that covers it with the fonts: option. See Text & paragraphs. |
image "…" skipped: … | An image could not be loaded or was refused: outside the working directory, not a public address, or (with 2.9.0) any source but a data: URI. The rest of the page renders. | See Layout & drawing. A data: URI always works. |
| barcode or QR messages | The value doesn't fit the symbology, for example an EAN-13 without 12 digits, or a non-EUR EPC code. | Validate the value in Ruby before rendering. |
decorated box split across pages | A box with a fill or border overflowed a page, so its background was left out. | Keep decorated boxes to content that fits a page. |
The list is replaced on every successful render and left alone when a render raises.
Note The messages come from the renderer's standard error, so the strings have
BINARY(ASCII-8BIT) encoding. Convert them before you log or display any that may contain accented text:Soli::PDF.last_warnings.map { |w| w.dup.force_encoding(Encoding::UTF_8) }.
#Turning warnings into failures
In tests, a warning usually means a broken template or incomplete data. Fail on it:
def render_strict(**args)
pdf = Soli::PDF.render(**args)
raise "PDF warnings: #{Soli::PDF.last_warnings.join('; ')}" if Soli::PDF.last_warnings.any?
pdf
end
In production, log them and serve the PDF anyway.
#Exceptions
Every exception the gem raises inherits from Soli::PDF::Error, so one rescue catches them all:
begin
pdf = Soli::PDF.render(template: template, data: data)
rescue Soli::PDF::Error => e
Rails.logger.error("PDF failed: #{e.class}: #{e.message}")
raise
end
#Soli::PDF::RenderError
render_pdf ran and exited with an error. There is no PDF. The exception carries:
| Method | Value |
|---|---|
#message | The renderer's message, stripped of surrounding whitespace. If the renderer printed nothing, it is render_pdf failed (<status>). |
#stderr | The renderer's full standard error. |
#status | The Process::Status of the finished process. |
Typical messages:
error: failed to parse JSON: unknown variant `bogus`, expected one of `paragraph`, `move`,
`image`, `table`, `hr`, `rect`, `line`, `qr`, `barcode`, `ellipse`, `list`, `chart`,
`repeat`, `if`, `unless`, `page_break`, `columns`, `box`, `at` at line 1 column 27
error: failed to parse JSON: key must be a string at line 1 column 2
error: font error: no usable fonts found in ["fonts", "font"]; provide a font directory …
error: io error: No such file or directory (os error 2)
| Message | Likely cause |
|---|---|
failed to parse JSON: unknown variant … | A misspelled element type. The message lists every valid type. |
failed to parse JSON: … elsewhere | A String passed as template: or data: that isn't valid JSON, or a field with the wrong type. The line and column refer to the JSON the gem sent. |
font error: no usable fonts found | The binary has no fonts/ directory next to it, and no fonts: were given. This happens with a custom SOLI_PDF_BIN build. |
io error: No such file or directory | A path given to stationery: or attachments: doesn't exist relative to the current directory. |
pdfa error: … | Factur-X output combined with password:, which PDF/A forbids. |
version `GLIBC_2.35' not found | The Linux binary needs glibc 2.35 or later. The system's C library is older, as on RHEL 9 or Debian 11. See Installation. |
When the template is a Hash you built, parsing errors point at the generated JSON. To find the element, render JSON.pretty_generate(template) in the playground, or check the type values in your template.
#Soli::PDF::BinaryNotFound
The gem could not find an executable to run:
unsupported OS: …orunsupported CPU: …: no release asset exists for this platform. Buildrender_pdfyourself and setSOLI_PDF_BIN.not executable: /path:SOLI_PDF_BINorSoli::PDF.binary_path=points to a file that is missing or not executable.
#Soli::PDF::DownloadError
The first-use download failed. There is no partial install: the archive is unpacked into a temporary directory and only moved into place once complete.
…: HTTP 404: the release asset doesn't exist for this version or platform.SHA-256 mismatch for …: the archive didn't match its published checksum. The gem refuses it. Retry, and report it if the problem persists.too many redirects fetching …: more than five redirects.- network errors (DNS, timeouts, TLS) are wrapped with the URL. The connection timeout is 10 s and the read timeout 120 s.
Avoid all of these in production by fetching the binary at build time. See Installation.
#ArgumentError
Raised before anything runs when the call itself is wrong: neither or both of data: and invoice:, xml: together with invoice:, or an unknown option. These are programming errors, so don't rescue them.
#In a Rails app
class ApplicationController < ActionController::Base
rescue_from Soli::PDF::RenderError do |error|
Rails.logger.error("PDF render failed: #{error.stderr}")
render plain: 'The document could not be generated.', status: :unprocessable_entity
end
end