{"record":{"id":"f9b3e89a8e2f161d","repo":"run-llama/liteparse","slug":"failed-to-load-pdfium-shared-library","errorCode":null,"errorMessage":"failed to load pdfium shared library","messagePattern":"failed to load pdfium shared library","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/pdfium/src/library.rs","lineNumber":69,"sourceCode":"/// // `lib` was dropped above — using `doc` here is a use-after-unlock.\n/// let _ = doc.page_count();\n/// ```\npub struct Library {\n    #[cfg(not(target_arch = \"wasm32\"))]\n    _guard: MutexGuard<'static, ()>,\n    #[cfg(target_arch = \"wasm32\")]\n    _private: (),\n}\n\nimpl Library {\n    /// Acquire the process-wide PDFium lock, blocking the current thread\n    /// until any other in-flight PDFium work has finished. Initializes the\n    /// library on first call.\n    ///\n    /// Multiple concurrent callers are serialized; only one `Library`\n    /// instance exists at a time.\n    pub fn init() -> Library {\n        Self::try_init().expect(\"failed to load pdfium shared library\")\n    }\n\n    /// [`Library::init`] that reports a missing or unloadable pdfium shared\n    /// library as [`PdfiumError::LibraryUnavailable`] instead of panicking.\n    /// Hosts that cannot afford a panic across an FFI boundary (a Node addon,\n    /// where an escaping panic aborts the process) should call this first;\n    /// the search path is described on `pdfium_sys::dynamic::load_default`.\n    pub fn try_init() -> Result<Library, PdfiumError> {\n        #[cfg(not(target_arch = \"wasm32\"))]\n        {\n            pdfium_sys::dynamic::load_default().map_err(|_| PdfiumError::LibraryUnavailable)?;\n            // Recover from poisoning: a panic mid-FFI may leave PDFium in\n            // an odd state, but subsequent calls should still be allowed\n            // (the worst case is that the next parse also fails cleanly).\n            let guard = pdfium_lock()\n                .lock()\n                .unwrap_or_else(|poisoned| poisoned.into_inner());\n            INIT.call_once(|| unsafe { ffi!(FPDF_InitLibrary()) });","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/run-llama/liteparse/blob/22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8/crates/pdfium/src/library.rs#L51-L87","documentation":"`Library::init()` acquires the process-wide PDFium lock and initializes PDFium, but first loads the shared library via `pdfium_sys::dynamic::load_default()`. When no loadable libpdfium can be found, `try_init()` returns `PdfiumError::LibraryUnavailable` and `init()` panics with this message. It means the pdfium shared library is missing, corrupt, or its dependencies cannot be resolved on this machine.","triggerScenarios":"Calling `Library::init()` (or anything that triggers it, e.g. `Document` loading) on a machine where `load_default()` fails: PDFIUM_LIB_PATH unset and no downloaded/cached/system libpdfium present; the library exists but has unresolved native dependencies (e.g. missing glibc/libjpeg on Linux); wrong architecture (x86_64 binary trying to load arm64 pdfium).","commonSituations":"Deploying to a slim Docker image or fresh CI machine without downloading the pdfium binary; PDFium downloaded for a different OS/arch; a Node addon host where the native pdfium library was not bundled; cross-platform distribution where the shared library was not shipped next to the executable.","solutions":["Set the PDFIUM_LIB_PATH env var to the directory containing the pdfium shared library (libpdfium.so / libpdfium.dylib / pdfium.dll) and retry.","Download the matching pdfium binary distribution for your platform (or use the build-script download path) and place it in one of the searched locations.","In panic-sensitive hosts (Node addon, FFI boundary), call `Library::try_init()` instead of `Library::init()` and handle `PdfiumError::LibraryUnavailable` gracefully.","If the file exists but still fails, run `ldd`/`otool -L` on the library to find missing transitive dependencies and install them, and confirm the architecture matches your build target."],"exampleFix":"// before\nlet lib = Library::init(); // panics: failed to load pdfium shared library\n// after (or: export PDFIUM_LIB_PATH=/opt/pdfium/lib before running)\nlet lib = Library::try_init().map_err(|e| {\n    eprintln!(\"pdfium unavailable: {e:?}; set PDFIUM_LIB_PATH to the lib dir\");\n    e\n})?;","handlingStrategy":"fallback","validationCode":"// check availability without panicking\nmatch Library::try_init() {\n    Ok(lib) => { /* proceed */ }\n    Err(PdfiumError::LibraryUnavailable) => {\n        eprintln!(\"pdfium missing; set PDFIUM_LIB_PATH to the dir containing libpdfium.so\");\n    }\n    Err(e) => { /* other error */ }\n}","typeGuard":"// Rust has no runtime type guard here; narrow via the typed error enum\nfn is_library_unavailable(e: &PdfiumError) -> bool {\n    matches!(e, PdfiumError::LibraryUnavailable)\n}","tryCatchPattern":"// avoid init()'s panic; use try_init and handle the error\nlet lib = Library::try_init()\n    .map_err(|e| anyhow!(\"pdfium shared library unavailable: {e:?}. Set PDFIUM_LIB_PATH.\"))?;","preventionTips":["Set PDFIUM_LIB_PATH in Docker images/CI so load_default() always finds the library","Download/bundle the platform-matching pdfium shared library as part of setup","In FFI hosts (Node addons), always use try_init() — an escaping panic aborts the process","Verify the library loads in CI smoke tests (ldd/otool for missing transitive deps and arch mismatch)"],"tags":["ffi","dynamic-loading","shared-library","rust"],"backgroundTag":"module-init-failed","analyzedSha":"22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8","analyzedAt":"2026-09-08T06:09:49.009Z","contentChangedAt":"2026-09-08T06:09:49.009Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}