Stirling-Tools/Stirling-PDF · error · Error

Failed to load page ${pageIndex}

Error message

Failed to load page ${pageIndex}

What it means

Thrown in createLinkAnnotation when m.FPDF_LoadPage(docPtr, pageIndex) returns a falsy (0/null) pointer. PDFium returns null when pageIndex is out of range or when the document/page is corrupt. Note the function bounds-checks destinationPage but does NOT bounds-check pageIndex against FPDF_GetPageCount before this call, so an out-of-range pageIndex reaches FPDF_LoadPage directly.

Source

Thrown at frontend/editor/src/core/utils/pdfLinkUtils.ts:122

    throw new Error("createLinkAnnotation: rect dimensions must be positive");
  }

  const m = await getPdfiumModule();
  const docPtr = await openRawDocumentSafe(data, password);

  try {
    const pageCount = m.FPDF_GetPageCount(docPtr);
    if (
      destinationPage !== undefined &&
      (destinationPage < 0 || destinationPage >= pageCount)
    ) {
      throw new RangeError(
        `createLinkAnnotation: destinationPage ${destinationPage} out of range [0, ${pageCount})`,
      );
    }

    const pagePtr = m.FPDF_LoadPage(docPtr, pageIndex);
    if (!pagePtr) throw new Error(`Failed to load page ${pageIndex}`);

    try {
      const pageHeight = m.FPDF_GetPageHeightF(pagePtr);

      const annotPtr = m.FPDFPage_CreateAnnot(pagePtr, FPDF_ANNOT_LINK);
      if (!annotPtr) {
        throw new Error("Failed to create link annotation");
      }

      try {
        // Set rect (convert from CSS top-left to PDF bottom-left origin)
        // FS_RECTF layout: { left, top, right, bottom } where top > bottom in PDF coords
        const pdfLeft = rect.x;
        const pdfTop = pageHeight - rect.y; // CSS y=0 → PDF top
        const pdfRight = rect.x + rect.width;
        const pdfBottom = pageHeight - rect.y - rect.height; // CSS bottom → PDF bottom

        const rectBuf = m.pdfium.wasmExports.malloc(4 * 4);

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Bounds-check pageIndex against FPDF_GetPageCount(docPtr) before FPDF_LoadPage, mirroring the existing destinationPage guard.
  2. Refresh the page count from the document right before annotation creation rather than caching it.
  3. Validate pageIndex is a non-negative integer at the API boundary.
  4. Wrap createLinkAnnotation at the caller and surface a page-specific error to the user.

Example fix

// before
const pagePtr = m.FPDF_LoadPage(docPtr, pageIndex);
if (!pagePtr) throw new Error(`Failed to load page ${pageIndex}`);

// after
const pageCount = m.FPDF_GetPageCount(docPtr);
if (pageIndex < 0 || pageIndex >= pageCount) {
  throw new RangeError(`pageIndex ${pageIndex} out of range [0, ${pageCount})`);
}
const pagePtr = m.FPDF_LoadPage(docPtr, pageIndex);
if (!pagePtr) throw new Error(`Failed to load page ${pageIndex} (corrupt page?)`);
Defensive patterns

Strategy: validation

Validate before calling

const pageCount = m.FPDF_GetPageCount(docPtr);
if (!Number.isInteger(pageIndex) || pageIndex < 0 || pageIndex >= pageCount) {
  throw new RangeError(`pageIndex ${pageIndex} out of range [0, ${pageCount})`);
}

Type guard

const isPageIndex = (i: number, pageCount: number): i is number =>
  Number.isInteger(i) && i >= 0 && i < pageCount;

Try / catch

try {
  await createLinkAnnotation(data, pageIndex, rect, options);
} catch (error) {
  if (/Failed to load page/.test((error as Error).message)) {
    // refresh page list and retry / notify user the page no longer exists
  }
  throw error;
}

Prevention

When it happens

Trigger: Passing a pageIndex >= pageCount or < 0 (no guard unlike destinationPage); operating on a PDF whose page table is corrupt; calling before the document finished parsing (pagePtr null due to a parse error swallowed upstream).

Common situations: Index computed from a stale page list (the user deleted/reordered pages); zero-based vs one-based index confusion; PDF produced by a faulty generator with a broken page tree.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/6938b18c84d88965. Report an issue: GitHub.