Skip to content

Exception: typed exception hierarchy

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.

Terminal window
composer require nextpdf/core:^3

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\UnregisteredCssDeviation

NextPdfException 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.

SymbolKindKey members
NextPDF\Contracts\ContextAwareExceptionInterfaceinterfacegetContext(): array<string, mixed>
NextPDF\Exception\NextPdfExceptionabstract classextends RuntimeException; getContext() (default [])
NextPDF\Exception\InvalidConfigExceptionfinalgetConfigKey(), getGivenValue(), getExpectedType(), getContext()
NextPDF\Exception\FontNotFoundExceptionfinalgetFontName(), getSearchPaths(), wasFallbackAttempted(), getContext()
NextPDF\Exception\SignatureExceptionfinalgetCertInfo(), getSignatureLevel(), getDetail(), getContext(); named ctors ltvCapabilityMissing(), tsaRequired(), httpClientMissing(), …
NextPDF\Exception\WriterExceptionfinalgetOutputPath(), getWriterState(), getContext()
NextPDF\Exception\PageLayoutExceptionfinalgetPageNumber(), getContext()
NextPDF\Exception\NotImplementedExceptionfinal$feature, $followUp
NextPDF\Exception\Strict\StrictModeViolationabstractextends NextPdfException
NextPDF\Exception\Strict\IncompatibleRenderingModeExceptionfinalextends 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.

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.

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;
}
}
  • Catch order matters. List leaf classes before NextPdfException; a leading catch (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 on getMessage().
  • NextPdfException is abstract; you cannot instantiate it directly. Throw a concrete leaf.
  • NotImplementedException is 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.

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.

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.

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.

  • /modules/core/contracts/ContextAwareExceptionInterface definition
  • /modules/core/observability/ — forwarding getContext() to APM
  • /modules/core/config/InvalidConfigException, NotImplementedException
  • /modules/core/support/DegradedException; WarningCode (NEXTPDF_W_*)
  • /modules/core/event/InvalidConfigException from addListener()

Glossary: context-aware exception · degradation policy