{"record":{"id":"c5f339d059b1b1fb","repo":"mozilla/pdf.js","slug":"kid-reference-not-found-in-parent-s-kids","errorCode":null,"errorMessage":"Kid reference not found in parent's kids.","messagePattern":"Kid reference not found in parent's kids\\.","errorType":"exception","errorClass":"FormatError","httpStatus":null,"severity":"error","filePath":"src/core/catalog.js","lineNumber":1667,"sourceCode":"          xref.fetchAsync(kid).then(obj => {\n            if (!(obj instanceof Dict)) {\n              throw new FormatError(\"Kid node must be a dictionary.\");\n            }\n            if (obj.has(\"Count\")) {\n              const count = obj.get(\"Count\");\n              if (Number.isInteger(count) && count >= 0) {\n                total += count;\n                return;\n              }\n              throw new FormatError(\"Count must be a (positive) integer.\");\n            }\n            // Page leaf node.\n            total++;\n          })\n        );\n      }\n      if (!found) {\n        throw new FormatError(\"Kid reference not found in parent's kids.\");\n      }\n      await Promise.all(kidPromises);\n      ref = parentRef;\n    }\n\n    this.pageIndexCache.put(pageRef, total);\n    return total;\n  }\n\n  get baseUrl() {\n    const uri = this.#catDict.get(\"URI\");\n    if (uri instanceof Dict) {\n      const base = uri.get(\"Base\");\n      if (typeof base === \"string\") {\n        const absoluteUrl = createValidAbsoluteUrl(base, null, {\n          tryConvertEncoding: true,\n        });\n        if (absoluteUrl) {","sourceCodeStart":1649,"sourceCodeEnd":1685,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/catalog.js#L1649-L1685","documentation":"Thrown by getPageIndex after scanning a parent's entire /Kids array without finding the current node's reference. The page tree is inconsistent: a node declares a /Parent that does not list it as a child, so the upward walk cannot determine the node's position.","triggerScenarios":"A page or intermediate node has a /Parent pointing to a /Pages dictionary whose /Kids array does not contain this node's ref. The `found` flag stays false through the loop and triggers the throw.","commonSituations":"PDFs where /Parent was reassigned during editing/merging but /Kids not updated; nodes orphaned by partial tree edits; copy-paste of pages between documents without relinking; corrupt stitchers.","solutions":["Catch the error and fall back to a linear getPage scan to locate the index.","Repair the file with qpdf or Ghostscript to rebuild a consistent page tree.","Regenerate the PDF so every node's ref appears in its declared parent's /Kids."],"exampleFix":"// before\nconst idx = await pdfDocument.getPageIndex(ref);\n\n// after\nlet idx = -1;\ntry {\n  idx = await pdfDocument.getPageIndex(ref);\n} catch (e) {\n  for (let i = 0; i < pdfDocument.numPages; i++) {\n    const p = await pdfDocument.getPage(i);\n    if (p.ref && p.ref.num === ref.num) { idx = i; break; }\n  }\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  idx = await pdfDocument.getPageIndex(ref);\n} catch (e) {\n  for (let i = 0; i < pdfDocument.numPages; i++) {\n    const p = await pdfDocument.getPage(i);\n    if (p.ref && p.ref.num === ref.num) { idx = i; break; }\n  }\n}","preventionTips":["When merging/splitting PDFs, always update both /Parent and /Kids consistently.","Use qpdf/Ghostscript to rebuild a consistent page tree after edits.","Provide a linear-scan fallback for untrusted documents."],"tags":["pdf","catalog","page-tree","corrupt-pdf","orphaned-node"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}