{"record":{"id":"44af86c90ce572e4","repo":"mozilla/pdf.js","slug":"extractpages-overlapping-pageindices","errorCode":null,"errorMessage":"extractPages: overlapping pageIndices.","messagePattern":"extractPages: overlapping pageIndices\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/editor/pdf_editor.js","lineNumber":994,"sourceCode":"   * @return {Promise<void>}\n   */\n  async extractPages(\n    pageInfos,\n    annotationStorage,\n    primaryDocument,\n    handler,\n    task\n  ) {\n    this.#primaryDocument = primaryDocument;\n    pageInfos = this.#resolveInsertAfterIndices(pageInfos);\n    const promises = [];\n    let newIndex = 0;\n    const reservePageSlot = newPageIndex => {\n      if (!Number.isInteger(newPageIndex) || newPageIndex < 0) {\n        throw new Error(\"extractPages: invalid page index.\");\n      }\n      if (this.oldPages[newPageIndex] !== undefined) {\n        throw new Error(\"extractPages: overlapping pageIndices.\");\n      }\n      // Reserve the slot immediately because page/image collection can be\n      // async.\n      this.oldPages[newPageIndex] = null;\n    };\n    const allDocumentData = [];\n\n    if (annotationStorage) {\n      this.#newAnnotationsParams = {\n        handler,\n        task,\n        newAnnotationsByPage: getNewAnnotationsMap(annotationStorage),\n        imagesPromises: AnnotationFactory.generateImages(\n          annotationStorage.values(),\n          this.xrefWrapper,\n          true\n        ),\n      };","sourceCodeStart":976,"sourceCodeEnd":1012,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/editor/pdf_editor.js#L976-L1012","documentation":"Plain Error thrown by reservePageSlot when a newPageIndex is already occupied in this.oldPages (slot !== undefined). It prevents two source pages from being written to the same output slot, which would silently lose data.","triggerScenarios":"pageIndices across multiple pageInfos that share a value (e.g., both [{pageIndices:[2]}] and [{pageIndices:[2]}]); a single pageInfo with duplicate pageIndices; an insertAfter resolution that collides with explicit pageIndices.","commonSituations":"Caller reuses pageIndices from different sources without de-duplication; off-by-one when manually shifting indices after an insert.","solutions":["De-duplicate all pageIndices across pageInfos before calling extractPages.","After resolving insertAfter yourself, ensure no slot is referenced twice.","Compute target slots programmatically (e.g., accumulate an offset) rather than hard-coding."],"exampleFix":"// before\npageInfos = [\n  { document: a, pageIndices: [0, 2] },\n  { document: b, pageIndices: [2, 4] },   // '2' overlaps\n];\n\n// after\npageInfos = [\n  { document: a, pageIndices: [0, 2] },\n  { document: b, pageIndices: [3, 4] },\n];","handlingStrategy":"validation","validationCode":"function assertNoOverlap(pageInfos) {\n  const seen = new Set();\n  for (const p of pageInfos) {\n    for (const idx of p.pageIndices ?? []) {\n      if (seen.has(idx)) throw new Error(`Overlapping pageIndex: ${idx}`);\n      seen.add(idx);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await editor.extractPages(pageInfos, ...);\n} catch (e) {\n  if (e.message === 'extractPages: overlapping pageIndices.') {\n    pageInfos = dedupeSlots(pageInfos);\n    return editor.extractPages(pageInfos, ...);\n  }\n  throw e;\n}","preventionTips":["Compute target slots programmatically (accumulating offset) instead of hard-coding.","De-duplicate all pageIndices across pageInfos in a Set-based check.","Re-run the contiguity/overlap check after any insertAfter resolution."],"tags":["editor","extract-pages","validation","page-index"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}