Stirling-Tools/Stirling-PDF · error · Error
Failed to export PDF
Error message
Failed to export PDF
What it means
Thrown in EmbedPdfViewer's export workflow when exportActions.saveAsCopy() returns a falsy value (null, undefined, or empty). saveAsCopy() is an EmbedPDF SDK method that serializes the currently loaded document (with annotations and redactions) into an ArrayBuffer. A null return means the SDK could not produce a valid PDF byte stream.
Source
Thrown at frontend/editor/src/core/components/viewer/EmbedPdfViewer.tsx:629
(redactionTrackerRef.current?.getPendingCount() ?? 0) > 0;
// Mark redactions as applied BEFORE committing, so the button stays enabled during the save process
// This ensures the button doesn't become disabled when pendingCount becomes 0
if (hadPendingRedactions || redactionsApplied) {
setRedactionsApplied(true);
}
if (hadPendingRedactions) {
console.log("[Viewer] Committing pending redactions before export");
redactionTrackerRef.current?.commitAllPending();
// Give a small delay for the commit to process
await new Promise((resolve) => setTimeout(resolve, 100));
}
// Step 1: Export PDF with annotations using EmbedPDF
const arrayBuffer = await exportActions.saveAsCopy();
if (!arrayBuffer) {
throw new Error("Failed to export PDF");
}
// Step 2: Convert ArrayBuffer to File
const blob = new Blob([arrayBuffer], { type: "application/pdf" });
const filename = currentFile.name || "document.pdf";
const file = new File([blob], filename, { type: "application/pdf" });
// Step 3: Create StirlingFiles and stubs for version history
// Only consume the current file, not all active files
const currentFileId = currentFileStableId;
if (!currentFileId) throw new Error("Current file ID not found");
const parentStub = selectors.getStirlingFileStub(currentFileId);
if (!parentStub) throw new Error("Parent stub not found");
const { stirlingFiles, stubs } = await createStirlingFilesAndStubs(
[file],
parentStub,View on GitHub (pinned to 9ef20dcab8)
Solutions
- Disable the export button until EmbedPDF signals the document is fully loaded (track a ready state).
- Check arrayBuffer.byteLength > 0 in addition to truthiness — an empty buffer is also invalid.
- Retry saveAsCopy() once after a short delay, as transient EmbedPDF state issues can self-resolve.
- Log exportActions state (session validity, document loaded flag) when the null is hit to diagnose the SDK's internal cause.
Example fix
// before
const arrayBuffer = await exportActions.saveAsCopy();
if (!arrayBuffer) {
throw new Error("Failed to export PDF");
}
// after
const arrayBuffer = await exportActions.saveAsCopy();
if (!arrayBuffer || arrayBuffer.byteLength === 0) {
throw new Error(
"EmbedPDF could not export the document. Ensure the document is fully loaded and try again."
);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check EmbedPDF document ready state before export
if (!embedPdfReady || !exportActions) {
showAlert('Document is still loading. Please wait before exporting.');
return;
}
// Validate the export action exists
if (typeof exportActions.saveAsCopy !== 'function') {
throw new Error('EmbedPDF export is not available in this session.');
} Type guard
function isValidPdfBuffer(data: unknown): data is ArrayBuffer {
return data instanceof ArrayBuffer && data.byteLength > 0;
} Try / catch
try {
const arrayBuffer = await exportActions.saveAsCopy();
if (!arrayBuffer || arrayBuffer.byteLength === 0) {
// Retry once after short delay
await new Promise(r => setTimeout(r, 200));
const retry = await exportActions.saveAsCopy();
if (!retry) throw new Error('EmbedPDF export failed after retry.');
return retry;
}
} catch (error) {
setErrorMessage(`PDF export failed: ${error instanceof Error ? error.message : 'unknown error'}`);
} Prevention
- Track EmbedPDF document-loaded state and disable export until ready.
- Check exportActions object is fully initialized before calling saveAsCopy.
- Validate arrayBuffer.byteLength > 0, not just truthiness.
- Test export with documents that have pending redactions separately from clean documents.
When it happens
Trigger: The EmbedPDF viewer has not finished loading the document, the document is in a corrupted state after redaction commits, the EmbedPDF session/license expired, or the SDK encountered an internal serialization error that it reported via null rather than throwing.
Common situations: User clicks export immediately after loading a large PDF before EmbedPDF finishes initialization. Pending redactions were committed (commitAllPending) but the internal state is inconsistent. EmbedPDF evaluation/session token expired mid-session.
Related errors
- No pages to export
- Failed to export PDF: ${error instanceof Error ? error.messa
- Current file ID not found
- File ${file.name} appears to be corrupted
- PDFium: failed to create destination document
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/20527e761b7fdf6c.
Report an issue: GitHub.