{"record":{"id":"af4c975732d39cab","repo":"mozilla/pdf.js","slug":"extractpages-sparse-pageindices","errorCode":null,"errorMessage":"extractPages: sparse pageIndices.","messagePattern":"extractPages: sparse pageIndices\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/editor/pdf_editor.js","lineNumber":1103,"sourceCode":"        }\n        reservePageSlot(newPageIndex);\n        promises.push(\n          document.getPage(i).then(page => {\n            this.oldPages[newPageIndex] = new PageData(page, documentData);\n          })\n        );\n      }\n    }\n    await Promise.all(promises);\n    if (this.oldPages.length === 0) {\n      throw new Error(\"extractPages: nothing to extract.\");\n    }\n    const copyCounts = new Map();\n    const documents = new Set();\n    for (let i = 0, ii = this.oldPages.length; i < ii; i++) {\n      const pageData = this.oldPages[i];\n      if (pageData === undefined) {\n        throw new Error(\"extractPages: sparse pageIndices.\");\n      }\n      if (pageData) {\n        const { page } = pageData;\n        const copyLevel = copyCounts.get(page) ?? 0;\n        copyCounts.set(page, copyLevel + 1);\n        pageData.copyLevel = copyLevel;\n        documents.add(pageData.documentData.document);\n      }\n    }\n    this.isSingleFile = documents.size === 1;\n    promises.length = 0;\n\n    this.#collectValidDestinations(allDocumentData);\n    this.#collectOutlineDestinations(allDocumentData);\n    this.#collectPageLabels();\n\n    for (const page of this.oldPages) {\n      if (page) {","sourceCodeStart":1085,"sourceCodeEnd":1121,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/editor/pdf_editor.js#L1085-L1121","documentation":"Plain Error thrown after collection if this.oldPages contains any undefined slot (a gap). Because reservePageSlot sets slots to null while collecting and then fills them with PageData, an undefined slot means pageIndices skipped an index (e.g., [0,2] leaves slot 1 undefined), producing a non-contiguous output document.","triggerScenarios":"pageIndices like [0, 2, 4]—skips 1 and 3; an insertAfter offset that leaves gaps; mixing auto-assigned and explicit indices incorrectly.","commonSituations":"Caller tries to insert pages at specific output positions but does not backfill the gaps with other content.","solutions":["Ensure pageIndices form a contiguous 0..N-1 range; fill any gap with another pageInfo or shift indices down.","Use insertAfter for insertions rather than hand-picking sparse indices.","After computing pageIndices, run a contiguity check: every integer in [0, max] must be present exactly once across all entries."],"exampleFix":"// before\npageInfos = [{ document, pageIndices: [0, 2] }];   // slot 1 missing\n\n// after\npageInfos = [{ document, pageIndices: [0, 1] }];\n// or fill the gap:\npageInfos = [\n  { document, pageIndices: [0] },\n  { document: other, pageIndices: [1] },\n  { document, pageIndices: [2] },\n];","handlingStrategy":"validation","validationCode":"function assertContiguous(pageInfos) {\n  const all = pageInfos.flatMap(p => p.pageIndices ?? []).sort((a, b) => a - b);\n  for (let i = 0; i < all.length; i++) {\n    if (all[i] !== i) throw new Error(`pageIndices are not contiguous at position ${i} (got ${all[i]})`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await editor.extractPages(pageInfos, ...);\n} catch (e) {\n  if (e.message === 'extractPages: sparse pageIndices.') {\n    pageInfos = compactPageIndices(pageInfos); // renumber to 0..N-1\n    return editor.extractPages(pageInfos, ...);\n  }\n  throw e;\n}","preventionTips":["After computing all pageIndices, ensure they cover 0..max with no gaps.","Use insertAfter for insertions; let pdf.js manage contiguous slots.","Add an integration test that pageInfos always yields contiguous output."],"tags":["editor","extract-pages","validation","page-index","contiguity"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}