Skip to content
getnextpdf.com

Rendering and I/O errors

These entries cover the rendering and input/output (I/O) exceptions raised while the HTML pipeline lays out content, the paged-media resolver assigns page geometry, the text shaper processes complex scripts, the typography stage breaks lines, the writer serializes a document, the reader parses an existing PDF, and the metadata stage reads an Extensible Metadata Platform (XMP) packet.

Two base hierarchies appear below, and the difference governs what diagnostic data you can read after a catch:

  • NextPdfException implements ContextAwareExceptionInterface::getContext(): array. The base implementation returns an empty array; a subclass carries structured keys only when it overrides getContext(). Subclasses that do not override it still expose their data through public readonly properties.
  • Several classes here extend PHP’s RuntimeException directly. They are not context-aware and have no getContext() method; read their getMessage() and any public properties instead.

Each entry names the exact class, the trigger condition, the context keys or public properties it carries, and the recovery path.

  • When it is thrown. The HTML layout engine raises this when content marked break-inside: avoid (a table cell whose break constraint is Avoid) has a measured height that exceeds the usable height of a single page. The engine cannot satisfy both the avoid-break constraint and the page boundary, so it fails rather than silently overflow.
  • Carried data. Extends NextPdfException but does not override getContext(), so getContext() returns an empty array. The diagnostic data is on public readonly properties: gridRow (int), gridCol (int), contentHeight (float, points), and pageHeight (float, points). The message names the cell coordinates and both heights.
  • Recovery. Remove the break-inside: avoid constraint on the offending cell, reduce the cell’s content so it fits one page, or increase the page size or reduce its margins so the usable height accommodates the content.
  • When it is thrown. Retained-mode layout primitives raise this when one of the four resource-budget tiers defined in architecture decision record ADR-020 is breached and the caller opted into a hard failure rather than the soft fallback. The default path does not throw: ContainerLayout::acceptChild() returns false, the caller falls back to block layout, and a warning is emitted. The exception is reserved for configuration-time validation and for tests that assert the exact breach tuple. The tiers are per-child (a captured child stream exceeds its cap), per-container (the Tier 1 node-count budget), per-document (the layout-pass or nesting-depth budget), and global (the SDK-wide 256 MB peak resident-set-size ceiling).
  • Carried data. Overrides getContext(), which returns a stable eight-key shape consumed by application performance monitoring (APM) tooling: budgetTier, exceededValue, budgetLimit, containerType, phase, breachOrigin, captureSize, and processedItemCount. The first four keys are the original v1.0.0 subset and are always populated; the latter four default to null or 0 when the constructor is called without them. getCausalWarningCode() maps the (tier, container-type) tuple to the WarningCode the soft-fallback path would have emitted.
  • Recovery. For a configuration breach, lower the requested value back into the documented envelope (for example, the retained node budget accepts 5,000 to 100,000 via Config::withRetainedNodeBudget()). For a content breach, reduce container nesting or node count, or rely on the default soft-fallback to block layout instead of opting into the hard-failure surface.
  • When it is thrown. The paged-media stage raises this, fail-closed, when a document declares a named @page <ident> { … } rule (bound to content through the page: <ident> property). Named pages from CSS Paged Media Level 3 §3.4 and Level 4 §3.2 — including the :first, :left, :right, and :blank pseudo-classes and named size: and rotate: overrides — are parsed but no production layout path consumes them. The engine refuses rather than emit the silently-incorrect default pagination that discarding the rule would produce.
  • Carried data. Overrides getContext(), which returns page_names (list of the distinct idents that triggered the failure, in source order), has_size_override (bool), has_rotate_override (bool), and has_pseudo_classes (bool). The same values are exposed on the pageNames, hasSizeOverride, hasRotateOverride, and hasPseudoClasses public properties.
  • Recovery. Remove the named @page <ident> rules and any page: <ident> bindings, and express the intended geometry through the supported unnamed @page { … } rule and its pseudo-class forms. Alternatively, pin to a future release that lands full named-page layout support.
  • When it is thrown. Text segmentation raises this when it needs the International Components for Unicode (ICU) line-break iterator but the require-ICU policy is active (NEXTPDF_REQUIRE_ICU=1) while the ext-intl extension and IntlBreakIterator are unavailable.
  • Carried data. Extends RuntimeException directly, so it is not context-aware and has no getContext(). It is a strict refinement of the generic exception the same code path previously threw, so existing catch (\RuntimeException) handlers continue to work.
  • Recovery. Install and enable ext-intl so the ICU break iterator is available, or unset NEXTPDF_REQUIRE_ICU to fall back to the non-ICU segmenter where the require-ICU policy is not mandatory.
  • When it is thrown. This is the base exception for the script-shaping service provider interface (SPI). It is not thrown directly today; concrete subtypes are thrown instead. Catch this type to handle any shaping failure in one place.
  • Carried data. Extends RuntimeException directly; not context-aware, no getContext().
  • Recovery. Branch on the concrete subtype. See NotYetImplementedException below for the only subtype shipped in the current release.
  • When it is thrown. Every placeholder script-shaper raises this from its shape() body for scripts whose concrete shaping is deferred (Mongolian and Tibetan). The shaping SPI seam is architecture-ready, but real shaping is pending a native-speaker-validated fixture. Raising an exception rather than a silent no-op surfaces accidental production wiring at runtime instead of emitting unshaped text into a PDF that claims tagged accessibility.
  • Carried data. Extends ScriptShaperException (and therefore RuntimeException), so it is not context-aware and has no getContext(). The diagnostic data is on its public readonly properties: bcp47LanguageTag (the BCP-47 tag of the run, such as mn-Mong or bo-Tibt) and missingCapability (the concrete capability the implementation lacks). The message includes both.
  • Recovery. Do not route runs in the unimplemented scripts through the shaper in production. Detect the language tag upstream and either fall back to a different rendering path or pin to a future release that lands shaping for the affected script.
  • When it is thrown. The writer raises this when a document contains a feature forbidden under the PDF 1.4 output profile (ISO 19005-1:2005 / PDF/A-1), which prohibits constructs introduced in later PDF versions.
  • Carried data. Extends NextPdfException but does not override getContext(), so getContext() returns an empty array. The diagnostic data is on its public readonly properties: feature (the rejected feature name), reason (why it is forbidden), and isoClause (the ISO clause reference). The message combines all three.
  • Recovery. Remove or replace the rejected feature with a PDF 1.4-compatible equivalent, or target a higher output profile that permits the feature.
  • When it is thrown. The writer raises this when a document contains a feature forbidden under the strict PDF 2.0 output profile. ISO 32000-2:2020 deprecates constructs that PDF 1.7 still permitted — most notably the Standard 14 Type 1 fonts (§9.6.2), which must be embedded in a conforming PDF 2.0 document.
  • Carried data. Same shape as Pdf14FeatureRejectedException: extends NextPdfException, does not override getContext() (returns an empty array), and exposes feature, reason, and isoClause as public readonly properties.
  • Recovery. Remediate the rejected feature — for example, embed the base 14 fonts — or take the documented escape hatch where one exists (for non-embedded base 14 fonts, Document::allowNonEmbeddedBase14()).
  • When it is thrown. PdfWriter::build() raises this at the entry point when the document’s encryptionMode is pubkey (a public-key recipient list) before the writer-side public-key stream-body encryption dispatch is wired. Refusing up front prevents silently emitting an unencrypted PDF the caller believed to be encrypted.
  • Carried data. Extends RuntimeException directly, so it is not context-aware and has no getContext(). It is a strict refinement of the generic exception the same site previously threw, so existing catch (\RuntimeException) handlers continue to work.
  • Recovery. Use a supported encryption mode (password-based encryption) instead of the public-key recipient list, or pin to a release that lands public-key encryption support. Do not treat the output as encrypted when this is thrown.
  • When it is thrown. The object-graph reader raises this, fail-closed, when an input PDF falls outside its supported envelope. The reader supports classic cross-reference tables (ISO 32000-2:2020 §7.5.4), cross-reference streams (§7.5.8), object-stream-compressed objects (§7.5.7), multi-revision /Prev chains (§7.5.6), and hybrid-reference files via /XRefStm (§7.5.8.4). Anything outside that envelope surfaces this exception rather than a partial or guessed parse. Named constructors map to the reason cases: encrypted(), damagedCrossReference(), cyclicReferenceChain(), nonConformantObjectStream(), irresolvableObjectCollision(), truncatedFile(), and crossReferenceOffsetOutOfBounds().
  • Carried data. Extends RuntimeException directly, so it is not context-aware and has no getContext(). It exposes a public readonly reason property of type UnsupportedPdfStructureReason (an enum) so callers branch on the precise category without parsing the message; an optional detail string and a previous throwable may add bounded, non-sensitive context. The default message is the reason’s non-leaking summary.
  • Recovery. Branch on reason. For EncryptedDocument, run a decrypt step before reading, since decryption is outside the reader’s scope. For DamagedCrossReference, TruncatedFile, or CrossReferenceOffsetOutOfBounds, treat the file as malformed or incomplete and re-acquire or repair the source. For CyclicReferenceChain, NonConformantObjectStream, or IrresolvableObjectCollision, the input violates the structural model and cannot be read as-is.
  • When it is thrown. The streaming XMP metadata reader raises this when an embedded XMP packet exceeds the configured byte ceiling. It is a defensive guard against entity-expansion and quadratic-blowup style inputs (a 128 MB peak ceiling against gigabyte-scale embedded XMP).
  • Carried data. Extends NextPdfException but does not override getContext(), so getContext() returns an empty array. The diagnostic data is on its public readonly properties: byteCount (the observed byte count) and cap (the configured cap in bytes). The message reports both.
  • Recovery. Reject or skip the oversized metadata as malicious or malformed. If a legitimate document genuinely needs a larger packet, raise the configured cap deliberately, weighing the memory-exhaustion risk the guard exists to prevent.