{"record":{"id":"6ff5b0d3c0783020","repo":"mozilla/pdf.js","slug":"gettextcontent-ignoring-circular-reference-ob","errorCode":null,"errorMessage":"getTextContent - ignoring circular reference: ${objId}","messagePattern":"getTextContent - ignoring circular reference: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/evaluator.js","lineNumber":2417,"sourceCode":"    disableNormalization = false,\n    keepWhiteSpace = false,\n    prevRefs = null,\n    intersector = null,\n  }) {\n    if (stream.isAsync) {\n      const bytes = await stream.asyncGetBytes();\n      if (bytes) {\n        stream = new Stream(bytes, 0, bytes.length, stream.dict);\n      }\n    }\n    sink ??= textSinkWrapper(null);\n\n    const objId = stream.dict?.objId;\n    const seenRefs = new RefSet(prevRefs);\n\n    if (objId) {\n      if (prevRefs?.has(objId)) {\n        throw new Error(\n          `getTextContent - ignoring circular reference: ${objId}`\n        );\n      }\n      seenRefs.put(objId);\n    }\n    // Ensure that `resources`/`stateManager` is correctly initialized,\n    // even if the provided parameter is e.g. `null`.\n    resources ||= Dict.empty;\n    stateManager ||= new StateManager(new TextState());\n\n    if (includeMarkedContent) {\n      markedContentData ||= { level: 0 };\n    }\n\n    const textContent = {\n      items: [],\n      styles: Object.create(null),\n      lang,","sourceCodeStart":2399,"sourceCodeEnd":2435,"githubUrl":"https://github.com/mozilla/pdf.js/blob/5903d58d58e4dd9ce6ffa3834aea8480f06b4ada/src/core/evaluator.js#L2399-L2435","documentation":"Thrown at the start of getTextContent when the stream's objId already appears in prevRefs. It is the text-extraction equivalent of the getOperatorList anti-recursion guard: a Form XObject re-entered during text extraction would otherwise loop. Like [85], this is a bare throw at method entry and is NOT suppressed by ignoreErrors.","triggerScenarios":"getTextContent traverses into a Form XObject whose stream chain re-enters a stream already on the ancestor path (cycle in the XObject reference graph).","commonSituations":"Malformed or malicious PDFs with cyclic Form XObject references; the symptom specifically affects text extraction / search rather than rendering.","solutions":["Wrap page.getTextContent() in try/catch and fall back (e.g. empty text or skip search) since ignoreErrors will not help here.","Repair the PDF to break the XObject cycle.","Upgrade PDF.js for hardened cycle detection."],"exampleFix":"// before\nconst tc = await page.getTextContent(); // rejects on cycle\n\n// after\nlet tc;\ntry {\n  tc = await page.getTextContent();\n} catch (e) {\n  console.warn('Text extraction failed (circular XObject):', e.message);\n  tc = { items: [], styles: {} };\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// ignoreErrors does NOT suppress this; catch at the getTextContent boundary.\nlet textContent;\ntry {\n  textContent = await page.getTextContent();\n} catch (e) {\n  if (/circular reference/.test(e.message)) {\n    textContent = { items: [], styles: {} }; // graceful empty result\n  } else throw e;\n}","preventionTips":["Never rely on ignoreErrors to cover cycle guards; it does not.","Give every getTextContent call a top-level try/catch in search/copy features.","Sanitize incoming PDFs to break XObject reference loops."],"tags":["pdf","circular-reference","xobject","malformed-pdf","text-extraction"],"backgroundTag":null,"analyzedSha":"5903d58d58e4dd9ce6ffa3834aea8480f06b4ada","analyzedAt":"2026-08-13T02:28:27.364Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}