Common issues, error messages, and how to resolve them.
Message: "Component has no computable layout" (or similar)
Cause: The root component has zero size and SwingToPDF can't determine how to lay it out. This typically happens when:
- The component has never been added to a visible frame
- Running in a headless environment (CI, Docker) with no display
- The component has zero preferred size
Fix:
// Option 1: Set an explicit size
panel.setSize(800, 600);
// Option 2: Pack a frame to trigger layout
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.pack();
// Option 3: Manual layout
panel.setSize(panel.getPreferredSize());
panel.doLayout();SwingToPDF attempts automatic layout via addNotify() + validate(), but this requires the component to have a non-zero preferred size.
Message: Varies -- wraps any rendering or I/O failure.
Common causes:
- Output file path is not writable (permissions, directory doesn't exist)
- Parent directory of the output path doesn't exist (create it first)
- I/O error writing to the output stream
- Internal rendering error
Fix: Check the exception's getCause() for the underlying error. Most commonly this is an IOException.
try {
exporter.export(path);
} catch (SwingPdfExportException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
// Check file permissions, disk space, path validity
}
}Message: "Failed to embed font: [font name]"
Cause: A font file was found but couldn't be loaded or parsed.
Common causes:
- Corrupt or truncated font file
- Unsupported font format (bitmap
.fonfiles are not supported) - File permission issues on the font file
Fix:
- Check the
getCause()for the specific parsing error - Use
e.getFont()to identify which font failed - Register a
FontResolverto point to a known-good copy of the font - As a workaround, change the component's font to one that can be embedded
Note: This exception is only thrown when a file is found but can't be parsed. When a font file can't be found, the library silently falls back to a standard PDF Type-1 font.
Symptom: Text in the PDF uses Helvetica/Times/Courier instead of the font set on the Swing component.
Cause: The library couldn't find the .ttf or .otf file for the font and fell back to a standard PDF base font.
Fix:
-
Add
--add-opensflags to enable JVM font path resolution:--add-opens java.desktop/java.awt=com.seaglassfoundry.swingtopdf --add-opens java.desktop/sun.font=com.seaglassfoundry.swingtopdf -
Check SLF4J logs for font fallback warnings. Enable debug logging to see which fonts are being resolved and which are falling back.
-
Register a custom FontResolver to explicitly provide font file paths:
.withFontResolver(font -> { if (font.getName().equals("ProblematicFont")) return Optional.of(Path.of("/path/to/font.ttf")); return Optional.empty(); })
-
Install the font on the system. On Linux CI servers, install
fontconfigand font packages:apt-get install fontconfig fonts-dejavu
Symptom: Warnings about illegal reflective access or missing opens.
Fix: Add all three --add-opens flags. See Getting Started.
The library works without these flags but uses slower font resolution (system directory scan) and may miss fonts loaded via Font.createFont().
Symptom: A JPanel subclass with custom painting is rasterized instead of rendered as vectors.
Cause: SwingToPDF detects paintComponent overrides and rasterizes the entire panel, because custom painting operations can't be decomposed into vector PDF primitives.
This is expected behavior. The raster fallback uses high-quality antialiasing and produces good-looking output. If you need vector output, consider:
- Moving the custom painting into a component that SwingToPDF has a handler for
- Restructuring the panel so the custom painting is in a small child component, while labels, text, and other standard components remain vectorized
Symptom: A JTable with many columns appears smaller than expected.
Cause: The table is wider than the printable area, so SwingToPDF scales it down to fit. A warning is logged when this happens.
Fix:
- Switch to
Orientation.LANDSCAPEfor more horizontal space - Use a larger page size (
PageSize.TABLOIDor a custom size) - Increase margins to give more effective width (counterintuitive, but sometimes narrower margins help)
- Reduce the number of visible columns or their preferred widths
Symptom: Only the visible portion of a scrollable component appears in the PDF.
Cause: You're using ExportMode.UI_SNAPSHOT, which intentionally captures only what's visible.
Fix: Switch to ExportMode.DATA_REPORT to export all content:
.exportMode(ExportMode.DATA_REPORT)Symptom: The PDF renders correctly but has no interactive form fields.
Cause: enableAcroForm() was not called on the builder.
Fix:
SwingPdfExporter.from(form)
.enableAcroForm() // required for interactive fields
.export(path);Symptom: Radio buttons in the PDF can all be selected simultaneously instead of being mutually exclusive.
Cause: The radio buttons are not in the same ButtonGroup in Swing, or group discovery failed.
Fix:
-
Make sure all related radio buttons are added to the same
ButtonGroup:ButtonGroup group = new ButtonGroup(); group.add(option1); group.add(option2); group.add(option3);
-
Add the
--add-opens java.desktop/javax.swingflag to enable reflection-based group discovery. Without it, the library uses behavioral testing, which is less reliable.
Symptom: Form fields are named field_1, field_2, etc. instead of meaningful names.
Cause: The Swing components don't have names set.
Fix: Call setName() on each form component before export:
textField.setName("customer_name");
checkBox.setName("terms_accepted");Symptom: The first export takes noticeably longer than subsequent exports.
Cause: One-time initialization costs:
- System font directory scan (building the font index)
- PDFBox initialization
Fix: This is normal. Subsequent exports in the same JVM session are faster because the font index is cached. To warm up, you can do a dummy export at application startup.
Symptom: Exporting a table with thousands of rows produces a very large PDF.
Cause: Each row generates vector drawing operations. Very large tables produce many PDF content streams.
Fix:
- Consider paginating the data at the application level (export only the relevant subset)
- If file size is critical, the
ImageHandlerhook can be used to JPEG-compress rasterized components
Symptom: LayoutException or rendering errors when running without a display.
Fix:
-
Set the component size explicitly before export:
panel.setSize(800, 600);
-
If using AWT/Swing features that require a display toolkit, set headless mode:
System.setProperty("java.awt.headless", "true");
-
On Linux, install X11 libraries if needed:
apt-get install libxrender1 libxtst6 libxi6
-
Alternatively, use Xvfb (virtual framebuffer) for full Swing toolkit support:
xvfb-run java -jar myapp.jar