Troubleshooting the NextPDF Laravel package
At a glance
Section titled “At a glance”Use this page to map each observable package failure to its verified source-level root cause. Each entry gives you the symptom, the cause, and the fix.
Install
Section titled “Install”composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configConceptual overview
Section titled “Conceptual overview”Most reported issues fall into five groups: discovery, container resolution, signing, queue jobs, and Hypertext Transfer Protocol (HTTP) filenames. The package fails loudly by design. Optional features that are not configured return null, and unsafe input raises typed exceptions. The symptom usually points directly to the cause.
API surface — symptom to cause
Section titled “API surface — symptom to cause”Discovery and boot
Section titled “Discovery and boot”| Symptom | Verified cause | Fix |
|---|---|---|
| Provider is not registered after install | Application disables discovery with extra.laravel.dont-discover | Remove the package from dont-discover, or register NextPdfServiceProvider manually in bootstrap/providers.php |
config('nextpdf') is empty | Configuration was not merged because no advertised binding was resolved (deferred provider) | Resolve any provides() entry, or confirm discovery with php artisan package:discover --ansi |
config/nextpdf.php not created by publish | Publish tag mismatch | Use the exact tag: php artisan vendor:publish --tag=nextpdf-config |
| RuntimeException: “NextPDF requires the ext-mbstring/ext-zlib PHP extension” | A required Hypertext Preprocessor (PHP) extension is missing at runtime | Install or enable mbstring and zlib in php.ini |
Container resolution
Section titled “Container resolution”| Symptom | Verified cause | Fix |
|---|---|---|
app(SignerInterface::class) returns null | Signing is disabled, or the certificate is empty in nextpdf.signature | Set signature.enabled = true and a valid signature.certificate; install nextpdf/premium to provide the signer concrete |
app(TsaClient::class) returns null | nextpdf.tsa.url is empty | Configure tsa.url (and credentials/pins as needed) |
| Class-not-found for a PDF/A version type | nextpdf.pdfa is non-null but nextpdf/premium is not installed | Install nextpdf/premium, or set pdfa back to null |
| Class-not-found resolving an e-invoice contract | Bindings are registered, but the Premium concretes are absent | Install nextpdf/premium; e-invoice contracts resolve lazily and fail only on the first resolve without Premium |
| Same document mutated across two logical operations | The document binding is a factory; you reused one resolved instance | Resolve a fresh PdfDocumentInterface per document |
A container without an entry throws a not-found exception on get()
(PHP Standard Recommendation 11 (PSR-11) §1.1.2). The e-invoice
contracts are bound, so the container’s has() returns true. The
missing Premium concrete raises the error at construction time, not the
container itself.
Queue jobs
Section titled “Queue jobs”| Symptom | Verified cause | Fix |
|---|---|---|
InvalidArgumentException: Path traversal sequences are not allowed | The output path contains a .. segment | Use an absolute, traversal-free path under your storage directory |
InvalidArgumentException: Stream wrappers are not allowed | The path uses a scheme like php:// | Use a plain filesystem path |
InvalidArgumentException: Output path contains null bytes | The path contains a \0 byte | Sanitize the path before dispatch |
InvalidArgumentException: Output path must end with .pdf extension | The path does not end in .pdf (case-insensitive) | Use a .pdf (or .PDF) suffix |
| Job runs but file is empty or wrong | The builder closure did not return the configured document | Return the document from the builder; the job saves the returned value |
| Job uses the wrong queue or timeout | nextpdf.queue.* is not set as expected | Set queue.queue, queue.connection, and queue.timeout; tries and backoff require subclassing |
Path checks run inside handle() on the worker, so a bad path fails
during execution, not at dispatch. This is intentional: the worker
validates the serialized queue payload where it consumes it.
HTTP responses and filenames
Section titled “HTTP responses and filenames”| Symptom | Verified cause | Fix |
|---|---|---|
Download filename is document.pdf unexpectedly | You passed an empty filename; the factory uses the default | Pass a non-empty filename |
| Filename lost its path or special characters | The filename sanitizer strips path separators, control characters, and null bytes | Pass only the base filename; this hardening is expected |
| Non-ASCII filename shows mojibake in some clients | The response emits Request for Comments 5987 (RFC 5987) filename*= for non-ASCII names; old clients read the ASCII fallback | Expected; provide an ASCII-safe name if a legacy client must match exactly |
Streamed response has no Content-Length | Streamed responses omit Content-Length by design (chunked output) | Expected; use the non-streamed inline()/download() if a length header is required |
Code sample — diagnostics
Section titled “Code sample — diagnostics”# Confirm the provider is discoveredphp artisan package:discover --ansi
# Inspect merged configurationphp artisan tinker --execute="dump(config('nextpdf.queue'));"<?php
declare(strict_types=1);
use NextPDF\Contracts\SignerInterface;
$signer = app(SignerInterface::class);
if ($signer === null) { // Signing not configured, or nextpdf/premium not installed. // Continue without a signature, or fail with a clear message.}Edge cases & gotchas
Section titled “Edge cases & gotchas”- With the deferred provider, a fresh install can look “broken” until
the first relevant resolve. Treat
package:discoverlisting the package as the success signal. - When
image_cache_mb = null, the package falls back to 50 MB; only0disables the cache. A “cache not disabling” report usually usednull. - When
signature.level = null, the package silently falls back to PDF Advanced Electronic Signatures (PAdES) B-B. An “unexpected B-B” report usually left the level unset.
Performance
Section titled “Performance”If the first requests on a long-lived worker are slow, the font registry is
parsing on demand. Populate nextpdf.preload_fonts so warmup runs once
at worker boot. See /integrations/laravel/configuration/ and /integrations/laravel/boot-and-discovery/ for details.
Security notes
Section titled “Security notes”The path and filename rejections are security controls, not bugs. Do not work around them by pre-decoding or relaxing the checks. Route file output through a controlled storage path instead. See /integrations/laravel/security-and-operations/.
Conformance
Section titled “Conformance”| Claim | Source | Clause | reference_id |
|---|---|---|---|
| Missing container entry throws not-found on get() | PSR-11 Container | §1.1.2 |
See also
Section titled “See also”- /integrations/laravel/install/ — discovery and publish steps
- /integrations/laravel/configuration/ — every key and its default
- /integrations/laravel/production-usage/ — dependency injection (DI) and queue patterns
- /integrations/laravel/security-and-operations/ — why the path checks exist