twentyhq/twenty · error · RuntimeError
PDF conversion failed
Error message
PDF conversion failed
What it means
Raised by thumbnail.py after invoking LibreOffice (`soffice --headless --convert-to pdf`) to render a .pptx to PDF as the first stage of thumbnail generation. The check combines the subprocess return code and the existence of the expected PDF on disk; failure of either trips the error. The subprocess's stderr is captured but not included in the message, so the cause must be read from result.stderr.
Source
Thrown at packages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/thumbnail.py:233
pdf_path = temp_dir / f"{pptx_path.stem}.pdf"
# Convert to PDF
print("Converting to PDF...")
result = subprocess.run(
[
"soffice",
"--headless",
"--convert-to",
"pdf",
"--outdir",
str(temp_dir),
str(pptx_path),
],
capture_output=True,
text=True,
)
if result.returncode != 0 or not pdf_path.exists():
raise RuntimeError("PDF conversion failed")
# Convert PDF to images
print(f"Converting to images at {dpi} DPI...")
result = subprocess.run(
["pdftoppm", "-jpeg", "-r", str(dpi), str(pdf_path), str(temp_dir / "slide")],
capture_output=True,
text=True,
)
if result.returncode != 0:
raise RuntimeError("Image conversion failed")
visible_images = sorted(temp_dir.glob("slide-*.jpg"))
# Create full list with placeholders for hidden slides
all_images = []
visible_idx = 0
# Get placeholder dimensions from first visible slideView on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Confirm `soffice` is installed and on PATH: `which soffice` and `soffice --version`.
- Capture and inspect result.stderr — replace the bare raise with one that appends `result.stderr` to see soffice's actual error.
- Clear a stale LibreOffice profile lock: remove `~/.config/libreoffice/.lock` (or run soffice with `-env:UserInstallation=file:///tmp/lo-profile` to isolate the profile).
- Ensure the temp dir is writable and has free space, and that pptx_path is a valid, unencrypted .pptx.
- Run soffice serially (it is not concurrency-safe per profile) if multiple thumbnails generate in parallel.
Example fix
# before
if result.returncode != 0 or not pdf_path.exists():
raise RuntimeError("PDF conversion failed")
# after — surface soffice's stderr so the cause is not lost
if result.returncode != 0 or not pdf_path.exists():
raise RuntimeError(
f"PDF conversion failed (rc={result.returncode}): "
f"{result.stderr.strip() or 'no stderr; check soffice install and path'}"
) Defensive patterns
Strategy: validation
Validate before calling
import shutil, subprocess
def ensure_soffice_available() -> None:
if shutil.which('soffice') is None:
raise RuntimeError('soffice (LibreOffice) not found on PATH; install libreoffice')
# also confirm it can start a headless convert
r = subprocess.run(['soffice', '--version'], capture_output=True, text=True)
if r.returncode != 0:
raise RuntimeError(f'soffice present but broken: {r.stderr}') Type guard
import shutil
def soffice_ready() -> bool:
return shutil.which('soffice') is not None Try / catch
try:
generate_thumbnails(pptx_path, out_dir)
except RuntimeError as e:
if 'PDF conversion failed' in str(e):
# most common causes: missing soffice, stale profile lock, or corrupt deck
if shutil.which('soffice') is None:
raise RuntimeError('Install libreoffice (soffice) to generate thumbnails.') from e
# retry once with an isolated profile to dodge the lock
generate_thumbnails(pptx_path, out_dir, soffice_profile='/tmp/lo-isolated')
else:
raise Prevention
- Bake libreoffice into the sandbox image; do not assume the host provides it.
- Run soffice with an isolated UserInstallation dir per process to avoid profile lock contention.
- Pre-validate the .pptx opens cleanly (e.g. Presentation() load succeeds) before invoking soffice.
When it happens
Trigger: soffice is not installed or not on PATH in the sandbox; soffice exits non-zero because the .pptx is corrupt or password-protected; a concurrent soffice instance holds the profile lock (LibreOffice is single-instance per user profile); the output directory is not writable; or the conversion 'succeeds' (rc 0) but writes the PDF to an unexpected path so pdf_path does not exist.
Common situations: Sandbox image missing the libreoffice package; a previous soffice process left a stale ~/.config/libreoffice lock; running thumbnail generation on a deck with embedded OLE objects soffice cannot render; disk-full in the temp dir.
Related errors
- Image conversion failed
- Slide index {idx} out of range (0-{total_slides - 1})
- Duplicate key found in JSON: '{key}'
- Found {len(errors)} validation error(s)
- Found {len(overflow_errors)} overflow error(s) and {len(warn
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/e3da6cc82525ff5d.
Report an issue: GitHub.