| name | pdfium-errors-runtime |
| description | Use when handling a PdfiumError returned at run time by pdfium-render: a wrong password, a corrupt or unreadable PDF, an index out of bounds, a flatten failure, or when rendered or extracted image colors look wrong with no error raised. Prevents unwrap-panics on recoverable errors, treating a wrong-password error as fatal, comparing errors with == when the enum has no PartialEq, and the silent BGRA-versus-RGBA channel swap. Covers the PdfiumError enum (82 variants in 0.9.1), the PdfiumInternalError codes wrapping FPDF_GetLastError, recoverable-versus-fatal classification, and the byte-order runtime bug across pdfium-render 0.8.x and 0.9.x. Keywords: pdfium-render, PdfiumError, PdfiumInternalError, PdfiumLibraryInternalError, PageIndexOutOfBounds, PageObjectIndexOutOfBounds, PasswordError, FormatError, FileError, PageFlattenFailure, FPDF_GetLastError, wrong password, corrupt PDF, index out of bounds, panic on unwrap, colors look wrong, blue and red swapped, image channels swapped, BGRA, RGBA, how do I handle pdfium errors, why is my PDF image the wrong color.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
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 by pdfium-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(())
}
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)?;
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() on load_pdf_from_* or an index access: a wrong password or a bad
index becomes a panic instead of a handled case.
- Treating every
PdfiumLibraryInternalError as fatal: PasswordError and
FormatError are recoverable.
err == PdfiumError::PageIndexOutOfBounds: the enum has no PartialEq.
- Feeding
as_raw_bytes() into the image crate: blue and red come out swapped.
- A
match on PdfiumError with 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: LoadLibraryError diagnosis, the fatal binding errors.
pdfium-syntax-document-loading: the loaders that surface PasswordError etc.
pdfium-syntax-rendering: PdfBitmap, set_reverse_byte_order, byte order.
pdfium-impl-output-formats: as_rgba_bytes vs as_raw_bytes when exporting.
pdfium-impl-page-manipulation: PageFlattenFailure from flatten().
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.