Exception: typed exception hierarchy
At a glance
Section titled “At a glance”Every exception that NextPDF throws extends one abstract base,
NextPdfException, so you can handle any engine error with a single catch.
Each domain exception implements ContextAwareExceptionInterface and exposes
structured diagnostic fields for logging and application performance monitoring
(APM) without parsing the message string.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”The hierarchy has three layers:
RuntimeException (PHP SPL) └── NextPdfException (abstract; implements ContextAwareExceptionInterface) ├── InvalidConfigException ├── FontNotFoundException ├── FontParsingException ├── ImageProcessingException ├── SignatureException ├── EncryptionException ├── WriterException ├── PageLayoutException ├── HtmlParsingException ├── CompressionException ├── NotImplementedException ├── … (23 domain exceptions total) └── Strict\StrictModeViolation (abstract) ├── Strict\IncompatibleRenderingModeException ├── Strict\OracleConformanceFailure └── Strict\UnregisteredCssDeviationNextPdfException extends RuntimeException from the Standard PHP Library
(SPL). Catching RuntimeException also catches NextPDF errors. Catching
NextPdfException narrows the handler to engine errors. Catch a leaf class for
targeted recovery. The Strict\ sub-tree groups conformance-mode violations
under the abstract StrictModeViolation, which itself extends
NextPdfException.
Context, not string codes. NextPDF identifies an error by its PHP type, not
by a string error code. The exception classes define no NPDF-#### code
constant. Instead, ContextAwareExceptionInterface::getContext() returns an
array<string, mixed> of snake_case primitive fields that are safe to serialize
into a log or APM payload. NextPdfException::getContext() returns [] by
default. Each domain exception overrides it with fields for that failure. For
example, FontNotFoundException::getContext() returns font_name,
search_paths, and fallback_attempted. WriterException returns
output_path and writer_state. InvalidConfigException returns
config_key, given_value, and expected_type. The stable NEXTPDF_W_*
string identifiers belong to the non-fatal WarningCode enum in the Support
module, not to exceptions.
Actionability. Each domain exception’s class docblock states who can act on
it: developer, infrastructure, or library caller. InvalidConfigException is a
developer error; fix the configuration. FontNotFoundException is a developer
or infrastructure error; verify the path or file permissions. WriterException
is an infrastructure error; check disk, permissions, or the output stream.
NotImplementedException is a caller error; remove the call or pin to a
release that lands the named follow-up. Several exceptions provide named
constructors for precise root causes: SignatureException::ltvCapabilityMissing(),
::tsaRequired(), and similar. Operators see the actual cause instead of a
generic message.
API surface
Section titled “API surface”| Symbol | Kind | Key members |
|---|---|---|
NextPDF\Contracts\ContextAwareExceptionInterface | interface | getContext(): array<string, mixed> |
NextPDF\Exception\NextPdfException | abstract class | extends RuntimeException; getContext() (default []) |
NextPDF\Exception\InvalidConfigException | final | getConfigKey(), getGivenValue(), getExpectedType(), getContext() |
NextPDF\Exception\FontNotFoundException | final | getFontName(), getSearchPaths(), wasFallbackAttempted(), getContext() |
NextPDF\Exception\SignatureException | final | getCertInfo(), getSignatureLevel(), getDetail(), getContext(); named ctors ltvCapabilityMissing(), tsaRequired(), httpClientMissing(), … |
NextPDF\Exception\WriterException | final | getOutputPath(), getWriterState(), getContext() |
NextPDF\Exception\PageLayoutException | final | getPageNumber(), getContext() |
NextPDF\Exception\NotImplementedException | final | $feature, $followUp |
NextPDF\Exception\Strict\StrictModeViolation | abstract | extends NextPdfException |
NextPDF\Exception\Strict\IncompatibleRenderingModeException | final | extends StrictModeViolation |
Full leaf set (23): BarcodeEncoderNotFoundException, BarcodeException,
CompressionException, ContentStreamBalanceException,
CssParserLimitExceededException, CssResolutionBudgetExceededException,
EncryptionException, FontNotFoundException, FontParsingException,
GraphicsStateBalanceException, HtmlParsingException,
ImageProcessingException, InvalidConfigException,
LinearizationInvariantException, LinearizationUnimplementedException,
MissingShadingResourceException, NotImplementedException,
PageLayoutException, PdfRViolationException, SignatureException,
TemplateException, UnsupportedAlgorithmException, WriterException.
Code sample — Quick start
Section titled “Code sample — Quick start”Catch any engine error by catching the base type.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;use NextPDF\Exception\NextPdfException;
try { $doc = Document::createStandalone(); $doc->addPage(); $doc->setFont('helvetica', '', 12); $doc->cell(0, 10, 'Hello'); $doc->save('out.pdf');} catch (NextPdfException $e) { \error_log($e->getMessage());}The runnable example examples/15-exception-handling.php exercises this
pattern.
Code sample — Production
Section titled “Code sample — Production”Recover at the leaf level, and send structured context to the log pipeline.
<?php
declare(strict_types=1);
use NextPDF\Contracts\ContextAwareExceptionInterface;use NextPDF\Core\Document;use NextPDF\Exception\FontNotFoundException;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
function render(Document $doc, LoggerInterface $logger): void{ try { $doc->setFont('Brand-Sans', '', 12); $doc->cell(0, 10, 'Invoice'); $doc->save('invoice.pdf'); } catch (FontNotFoundException $e) { // Targeted recovery: fall back to a built-in font. $logger->warning($e->getMessage(), $e->getContext()); $doc->setFont('helvetica', '', 12); $doc->save('invoice.pdf'); } catch (NextPdfException $e) { // Any other engine error: structured context, then rethrow. $context = $e instanceof ContextAwareExceptionInterface ? $e->getContext() : []; $logger->error($e->getMessage(), $context); throw $e; }}Edge cases & gotchas
Section titled “Edge cases & gotchas”- Catch order matters. List leaf classes before
NextPdfException; a leadingcatch (NextPdfException)swallows every subclass. getContext()keys use snake_case, and values are primitives or lists of primitives, with no nested objects. The payload is safe for JavaScript Object Notation (JSON) serialization.- The base
NextPdfException::getContext()returns[]. A subclass that does not override it carries no structured fields. In that case, rely ongetMessage(). NextPdfExceptionis abstract; you cannot instantiate it directly. Throw a concrete leaf.NotImplementedExceptionis intentionally loud. It signals a deliberately absent implementation, not a transient failure. Do not retry it.Strict\*violations indicate a conformance-mode contract breach, not a recoverable runtime error. Treat them as configuration or input defects.- There is no string error-code constant. Match on the exception type.
Forward
getContext()for machine consumers.
Performance
Section titled “Performance”Exception construction performs one object allocation plus the sprintf call
that builds the message: O(1). getContext() returns a small associative array
built from already-held fields: O(1) in the number of fields. Exceptions run on
the failure path, not the hot path. The cost is negligible compared with the
work that failed. The default performance_budget for this reference page is
wall_ms: 1500, peak_mb: 64.
Security notes
Section titled “Security notes”Context fields can carry document-derived detail. FontNotFoundException
includes filesystem search paths, WriterException includes the output path,
and InvalidConfigException includes the supplied value. Before forwarding
context to a low-trust log sink, scrub fields or pass only an allowlist of keys,
because paths and values may reveal deployment layout or user input. Exception
messages are human-readable and may include the same detail. Do not show raw
messages to end users in a security-sensitive context. SignatureException
deliberately binds the concrete root cause, such as a missing package or an
empty Uniform Resource Locator (URL) for a Time Stamping Authority (TSA), to
the message so operators can triage without searching call sites. That detail
is operator-facing, not end-user-facing.
Conformance
Section titled “Conformance”This module defines an engine error model and carries no normative standard
citation. Exceptions raised for standards violations, for example
PdfRViolationException or Strict\OracleConformanceFailure, reference their
governing clause on the module that detects the violation, not here.
See also
Section titled “See also”/modules/core/contracts/—ContextAwareExceptionInterfacedefinition/modules/core/observability/— forwardinggetContext()to APM/modules/core/config/—InvalidConfigException,NotImplementedException/modules/core/support/—DegradedException;WarningCode(NEXTPDF_W_*)/modules/core/event/—InvalidConfigExceptionfromaddListener()
Glossary: context-aware exception · degradation policy