pdfium-render: Runtime Errors
Handling errors that surface while a PDF is being processed: loading, page access,
object access, text, rendering, and saving. Every fallible pdfium-render function
returns Result<T, PdfiumError>. This skill owns the runtime error surface.
Diagnosing a failed library bind is pdfium-errors-binding.
All API names below are verified against docs.rs/pdfium-render 0.9.1. The default
target is the 0.9.x API; 0.8.x differences are flagged inline.
The PdfiumError Enum
PdfiumError has 82 variants in 0.9.1. It implements Display, Debug, and
std::error::Error (since 0.7.26). It does NOT implement Clone and does NOT
implement PartialEq.
The variants fall into two groups:
- Data-carrying variants wrap another error type:
PdfiumLibraryInternalError(PdfiumInternalError): PDFium's own error, the single most important variant (see below).IoError(std::io::Error): a filesystem error during load or save.LoadLibraryError(...)/LoadLibraryFunctionNameError(String): binding failures, owned bypdfium-errors-binding.- Conversion errors:
ParseHexadecimalColorError(ParseIntError),CStringConversionError(IntoStringError),UnableToConvertPdfiumColorValueToRustu8(TryFromIntError),InvalidUserFontPath(NulError).
- Data-free logic and bounds variants, for example
PageIndexOutOfBounds,PageObjectIndexOutOfBounds,PageAnnotationIndexOutOfBounds,CharIndexOutOfBounds,NoPagesInDocument,UnknownBitmapFormat,PageFlattenFailure,CannotMoveObjectAcrossDocuments,PageObjectsCollectionIsImmutable,DataBufferLengthMismatch,OwnershipNotAttachedToDocument.
The full variant list is in references/methods.md.
The Critical Variant: PdfiumLibraryInternalError
PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError) carries the error
PDFium itself reported through FPDF_GetLastError(). Loading a PDF that exists but
cannot be opened always surfaces here. PdfiumInternalError has six variants:
| Variant | PDFium code | Meaning | Class |
|---|---|---|---|
Unknown |
1 | Generic, no detail available | depends on context |
FileError |
2 | File system error reading the document | recoverable |
FormatError |
3 | Document is not valid PDF / parse failure | recoverable |
PasswordError |
4 | Wrong or missing password | recoverable |
SecurityError |
5 | Document security settings block the load | recoverable |
PageError |
6 | A page failed to load (internal error) | recoverable |
ALWAYS match the inner PdfiumInternalError before deciding what to do: a
PasswordError means re-prompt and retry, a FormatError means skip the file.
NEVER treat every PdfiumLibraryInternalError the same.
Decision Tree: recoverable or fatal
Got a PdfiumError. Which variant?
LoadLibraryError / LoadLibraryFunctionNameError
-> FATAL. No bound library means nothing works. See pdfium-errors-binding.
PdfiumLibraryInternalError(PasswordError)
-> RECOVERABLE. Re-prompt for the password, retry load_pdf_from_* with Some(pw).
PdfiumLibraryInternalError(FileError | FormatError | SecurityError | PageError)
-> RECOVERABLE per document. Log and skip this PDF; keep processing the rest.
PageIndexOutOfBounds / PageObjectIndexOutOfBounds / CharIndexOutOfBounds / ...
-> RECOVERABLE. A programming or input error. Clamp the index or skip the item.
IoError(_)
-> RECOVERABLE. A filesystem problem; retry, fall back, or report it.
Image colors look wrong but NO error was raised
-> Not an error. A byte-order bug. See "The Silent Byte-Order Bug" below.
Pattern: Handle a Load Failure
load_pdf_from_* is where most recoverable runtime errors appear. Match the inner
PDFium error to react correctly:
use pdfium_render::prelude::*;
fn open(pdfium: &Pdfium, path: &str, password: Option<&str>)
-> Result<(), PdfiumError>
{
match pdfium.load_pdf_from_file(path, password) {
Ok(document) => {
println!("{} has {} pages", path, document.pages().len());
Ok(())
}
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::PasswordError,
)) => {
eprintln!("{}: wrong password", path);
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::PasswordError,
))
}
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::FormatError,
)) => {
eprintln!("{}: not a valid PDF, skipping", path);
Ok(()) // skip, keep going
}
Err(other) => Err(other),
}
}
A wrong password is a normal, expected outcome; ALWAYS handle it as recoverable.
Pattern: Bounds Errors Are Inputs, Not Crashes
Index-based access returns a Result. An out-of-range index returns a bounds
variant such as PageIndexOutOfBounds. ALWAYS handle it; NEVER .unwrap() an
index access on input you did not validate:
match document.pages().get(requested_index) {
Ok(page) => process(&page),
Err(PdfiumError::PageIndexOutOfBounds) => {
eprintln!("page {} does not exist", requested_index);
}
Err(e) => return Err(e),
}
NoPagesInDocument is the related whole-document case: a structurally valid PDF
with zero pages. Check it before iterating.
Pattern: Matching Without PartialEq
PdfiumError does not implement PartialEq, so err == PdfiumError::X does not
compile. ALWAYS classify with match or the matches! macro:
fn is_recoverable(error: &PdfiumError) -> bool {
matches!(
error,
PdfiumError::PageIndexOutOfBounds
| PdfiumError::PageObjectIndexOutOfBounds
| PdfiumError::CharIndexOutOfBounds
| PdfiumError::NoPagesInDocument
| PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::PasswordError
| PdfiumInternalError::FormatError
| PdfiumInternalError::FileError,
)
)
}
PdfiumError also does not implement Clone. NEVER try to clone an error to keep
a copy; propagate it with ? or move it where it is needed.
Pattern: Propagation with ? and anyhow
Because PdfiumError implements std::error::Error and Display, it composes
with ?, with Box<dyn std::error::Error>, and with the anyhow crate:
fn page_count(path: &str) -> anyhow::Result<usize> {
let pdfium = Pdfium::default();
let document = pdfium.load_pdf_from_file(path, None)?; // PdfiumError -> anyhow
Ok(document.pages().len() as usize)
}
Use ? in pipeline code where any error aborts the run; use explicit match at
the boundary where an error must be classified as recoverable or fatal.
The Silent Byte-Order Bug
Not every runtime fault raises a PdfiumError. PDFium's native bitmap format is
BGRA: blue and red are swapped relative to the RGBA8 layout the image crate
expects. Feeding native bytes into an RGBA consumer produces an image with blue
and red exchanged, and NO error is returned (issue #50).
PdfBitmap::as_raw_bytes()returns bytes in the bitmap's NATIVE format (BGRA).PdfBitmap::as_rgba_bytes()returns bytes normalized to RGBA8 regardless of the native format (added 0.8.16).
ALWAYS use as_rgba_bytes() when handing pixels to the image crate or any RGBA
consumer. ALWAYS use as_image() for a ready DynamicImage. Reserve
as_raw_bytes() for code that explicitly handles the native byte order, and use
PdfRenderConfig::set_reverse_byte_order(true) to flip the order at render time.
Full rendering detail is in pdfium-syntax-rendering and pdfium-impl-output-formats.
Version Notes
| Item | 0.8.x | 0.9.x | Note |
|---|---|---|---|
PdfiumError implements Error + Display |
yes (since 0.7.26) | yes | anyhow compatible |
as_rgba_bytes() |
added 0.8.16 | present | normalized RGBA, fixes byte order |
PdfiumError variant count |
grows per release | 82 in 0.9.1 | never assume an exhaustive match stays exhaustive |
PdfiumError is marked non-exhaustive in practice: a match on it ALWAYS needs a
_ => arm so a crate upgrade that adds a variant still compiles.
Anti-Patterns (summary)
.unwrap()onload_pdf_from_*or an index access: a wrong password or a bad index becomes a panic instead of a handled case.- Treating every
PdfiumLibraryInternalErroras fatal:PasswordErrorandFormatErrorare recoverable. err == PdfiumError::PageIndexOutOfBounds: the enum has noPartialEq.- Feeding
as_raw_bytes()into theimagecrate: blue and red come out swapped. - A
matchonPdfiumErrorwith no_ =>arm: breaks on the next crate upgrade.
Each anti-pattern with the failure detail and fix: see references/anti-patterns.md.
Cross-References
pdfium-errors-binding:LoadLibraryErrordiagnosis, the fatal binding errors.pdfium-syntax-document-loading: the loaders that surfacePasswordErroretc.pdfium-syntax-rendering:PdfBitmap,set_reverse_byte_order, byte order.pdfium-impl-output-formats:as_rgba_bytesvsas_raw_byteswhen exporting.pdfium-impl-page-manipulation:PageFlattenFailurefromflatten().
Reference Files
references/methods.md: the full PdfiumError variant list and the error types.references/examples.md: verified error-handling Rust code.references/anti-patterns.md: real failures, why they fail, the fix.
Source
Verified 2026-05-20 against https://docs.rs/pdfium-render/latest/pdfium_render/
(prelude enum.PdfiumError.html and enum.PdfiumInternalError.html). Runtime
anti-patterns including the byte-order bug (issue #50) are recorded in
vooronderzoek-pdfium.md sections 7 and 8.