Skip to content
getnextpdf.com

Runtime and support errors

These entries document the exceptions raised by the runtime support layer: the degradation policy, the cURL-backed HTTP transport, the resilience circuit breaker, the Security Information and Event Management (SIEM) emitter, the render manifest, PDF inspection, and the chaos-engineering subsystem.

Most NextPDF exceptions extend NextPdfException, which implements ContextAwareExceptionInterface and exposes getContext(): array for structured diagnostic logging. A subclass populates that array only when it overrides getContext(); the base returns an empty array. Three exceptions on this page (DegradedException, CircuitBreakerOpenException, and InspectException) extend PHP’s RuntimeException directly and expose their data through public readonly properties instead of getContext(). Each entry below names the exact properties or context keys the class carries, taken from source.

  • Thrown when. The rendering pipeline encounters a degraded capability that violates the active degradation policy. Under DegradationPolicy::Strict, any high-impact degradation (ComplianceRisk, SemanticLoss, or Blocking) raises it; under DegradationPolicy::Balanced, only a Blocking impact raises it.
  • Class. Extends RuntimeException directly (not NextPdfException), so it carries no getContext().
  • Data carried. Two public readonly properties: $capability (the Capability value object that triggered the rejection, including its id, status, reason, fallbackTarget, and impact) and $policy (the DegradationPolicy active at rejection time). The message has the form Feature "<id>" is <status>: <reason> (policy: <policy>).
  • Recovery. Inspect $capability to identify the missing feature and its cause. Either install the component that the capability requires, accept a lower-impact configuration, or relax the policy from Strict to Balanced when the degradation is acceptable for the use case. Call $capability->isAvailable() / isDegraded() to drive user-facing messaging.

These three exceptions originate in the cURL-backed PSR-18 client and its security-aware decorator. The first two extend NextPdfException but do not override getContext(), so their getContext() returns an empty array; diagnostic data is reached through the PSR-18 getRequest() accessor and the chained previous throwable.

  • Thrown when. The HTTP request cannot be completed because of a network-level fault: Domain Name System (DNS) resolution failure, connection timeout, or Transport Layer Security (TLS) handshake error. It is also the class the security-aware decorator raises for a security rejection (Server-Side Request Forgery refusal, DNS-rebinding refusal, or a denied redirect).
  • Class. Implements PSR-18 Psr\Http\Client\NetworkExceptionInterface.
  • Data carried. getRequest() returns the failed RequestInterface. The originating transport error, when present, is the chained previous throwable. getContext() returns an empty array (the base default).
  • Recovery. A network fault may be transient — retry with backoff if the request is idempotent. A security rejection is not transient and must fail closed: do not retry; correct the target URL or the SSRF policy instead. Read the message and previous throwable to tell the two apart.
  • Thrown when. The request itself cannot be sent because it is malformed, for example an invalid URL or a request that failed SSRF validation before any network call.
  • Class. Implements PSR-18 Psr\Http\Client\RequestExceptionInterface.
  • Data carried. getRequest() returns the offending RequestInterface; the underlying cause, when present, is the chained previous throwable. getContext() returns an empty array.
  • Recovery. This is a caller-input or policy defect, not a transient fault. Do not retry unchanged. Fix the request URL, headers, or body, or adjust the SSRF allowlist if the target is legitimately permitted, then re-issue the request.
  • Thrown when. Internally, inside SecurityAwareHttpClient, to mark a genuinely transient inner-transport fault (DNS, connection, or timeout raised by the inner PSR-18 client) as eligible for the bounded retry budget. It is the only retry-eligible class the decorator’s retry loop recognises; an unwrapped exception (a decorator-raised security rejection) is treated as fatal.
  • Class. Implements PSR-18 Psr\Http\Client\NetworkExceptionInterface. Marked @internal — it is created and unwrapped entirely within SecurityAwareHttpClient and never escapes the decorator.
  • Data carried. getRequest() returns the failed request. The original inner-transport ClientExceptionInterface is preserved as the chained previous throwable (getPrevious()) and re-surfaced verbatim to the caller once the retry budget is exhausted, so the public PSR-18 contract is unchanged. getContext() returns an empty array.
  • Recovery. Application code does not catch this type directly. Catch the re-surfaced inner exception that the decorator returns after the retry budget is spent, and treat repeated transient failures as an upstream availability problem.
  • Thrown when. A CircuitBreaker in the CircuitBreakerState::Open state rejects a call fail-fast, before any downstream invocation. It exists to let callers distinguish “the remote service is unreachable right now” (a transient transport fault, worth degrading) from “the connection pool would have been exhausted by this call” (fail-fast, no network attempted) — the batch denial-of-service mitigation required for Public Key Infrastructure (PKI) clients.
  • Class. Extends RuntimeException directly, so it carries no getContext().
  • Data carried. Two public readonly properties: $breakerName (the identifier of the open breaker) and $secondsUntilHalfOpen (the approximate cooldown remaining before the breaker transitions to half-open). The message has the form Circuit breaker "<name>" is OPEN (cooldown ~<n>s remaining); call rejected fail-fast.
  • Recovery. Do not hammer the breaker — wait at least $secondsUntilHalfOpen before retrying, or degrade the operation. No network call was attempted, so this is not evidence the remote service itself failed; it is back-pressure protecting the connection pool.
  • Thrown when. A SIEM event emitter cannot persist or chain a record. It surfaces filesystem-level failures (open, lock, seek, write, fflush, read) and hash-chain integrity faults (chain: out-of-order index, malformed tail record, or JSON round-trip drift) shared across the hash-chain event log and the JSON-lines file emitter adapters.
  • Class. Extends NextPdfException and overrides getContext().
  • Context keys. operation (one of open, lock, seek, write, fflush, read, chain), path (the target log path), and detail (a human-readable detail such as byte counts or expected-versus-actual index). These are also reachable through getOperation(), getPath(), and getDetail(). The message has the form SIEM emitter <operation> failed for <path>: <detail>.
  • Recovery. This is actionable by infrastructure or SecOps, not by application logic. Verify the log-volume mount, directory permissions, available file descriptors, and filesystem health. A chain operation failure indicates a tamper or corruption signal in the audit log and should be investigated, not silently retried.
  • Thrown when. A RenderManifest cannot be constructed, deserialized, or read because of a structural, type, or schema-compatibility error. The manifest is a versioned public contract submitted by every transport (CLI, Laravel queue, Symfony, the SaaS API), so a malformed or incompatible manifest is surfaced directly rather than coerced to defaults.
  • Class. Extends NextPdfException and overrides getContext(). Named constructors set a stable machine-readable code in the SPEC-MANIFEST-* namespace:
    • RenderManifestException::shape()SPEC-MANIFEST-001 — shape or type error during RenderManifest::fromArray().
    • RenderManifestException::incompatibleVersion()SPEC-MANIFEST-002 — incompatible major schema version (cannot be read).
    • RenderManifestException::missingField()SPEC-MANIFEST-003 — required field missing during builder finalization.
    • RenderManifestException::unsupported()SPEC-MANIFEST-004 — a well-formed manifest references an input or template the current renderer cannot resolve (for example a URI input or a host-only template engine).
  • Context keys. manifest_code (the SPEC-MANIFEST-* identifier) and reason (the human-readable failure description). These are also reachable through getManifestCode() and getReason(). The message has the form [<code>] <reason>.
  • Recovery. Branch on manifest_code. For SPEC-MANIFEST-001 and SPEC-MANIFEST-003, fix the manifest payload (correct the field type or supply the missing field). For SPEC-MANIFEST-002, regenerate the manifest against a supported major schema version or upgrade the renderer. For SPEC-MANIFEST-004, supply an input or template engine the current edition can resolve.
  • Thrown when. PDF inspection fails.
  • Class. Extends RuntimeException directly (not NextPdfException), so it carries no getContext().
  • Data carried. Two public readonly properties: $inspectCode (a machine-readable code in the INSPECT-* namespace) and $retryable (a boolean indicating whether the caller should retry — for example when an inspection sidecar is temporarily down). The originating cause, when present, is the chained previous throwable.
  • Recovery. Branch on $inspectCode for the specific failure class. When $retryable is true, retry with backoff because the failure is expected to be transient (such as a sidecar restart); when false, treat the input or configuration as the defect and do not retry unchanged.
  • Thrown when. ChaosScenarioRunner::writeReport() cannot persist the aggregated chaos-day report to disk. It is a domain-typed replacement for a generic runtime error, so callers can catch the specific report-disk failure without conflating it with errors raised inside the scenario simulators themselves (the runner captures those as ChaosOutcome fields).
  • Class. Extends NextPdfException and overrides getContext().
  • Context keys. output_path (the absolute path the runner attempted to write). It is also reachable through getOutputPath(). The message has the form ChaosScenarioRunner: failed to write report to "<path>".
  • Recovery. This is a write-side failure of the report sink, not of the scenarios. Verify the output directory exists and is writable and that disk space is available, then re-run the report write. The chaos outcomes themselves are unaffected.
  • Thrown when. A retrieval endpoint (for example a Voyage Retrieval Augmented Generation service) is unavailable and the system either falls back to cached-only mode or fails closed.
  • Class. Extends NextPdfException and overrides getContext().
  • Context keys. mode (the operating mode after the failure — CACHED_ONLY when results are served from the semantic cache only, or FAIL_CLOSED when the request is refused entirely with no stale data) and endpoint (the endpoint that became unreachable). These are also reachable through getMode() and getEndpoint(). The message has the form Retrieval endpoint "<endpoint>" is unavailable; operating in <mode> mode.
  • Recovery. Read mode to learn how the system degraded. Under CACHED_ONLY, results may be stale; refresh once the endpoint recovers. Under FAIL_CLOSED, the request was refused by design and must be retried after the endpoint is reachable. Restore endpoint connectivity (network, credentials, service health) before depending on fresh retrieval.