· NextPDF · Engineering · 2 min read
An engine that refuses to guess
The most useful thing a PDF engine can do is tell you the truth about what it cannot do. Here is the design philosophy behind NextPDF's typed failures and fail-closed defaults.
PDF is old enough to have opinions, and strict enough to punish guesses. A lot of PDF tooling hides that strictness behind a permissive surface: ask for something the format does not allow, and you get a plausible-looking file that quietly does the wrong thing. The bug surfaces weeks later, in production, on a document that matters.
NextPDF is built on the opposite instinct.
Refuse to guess
When the engine cannot do exactly what you asked — an unsupported colour space, a signature constraint it cannot satisfy, an input it cannot parse — it does not improvise. It raises a typed error that names the boundary. You learn at call time, with a stack trace, not from a customer three weeks on.
This is a deliberate trade. It makes the easy path slightly stricter so the hard path is honest. For software that signs contracts and produces compliance artifacts, that trade is the only one worth making.
Fail closed, not open
Security-relevant defaults fail closed. A signature operation that cannot meet its stated profile fails rather than producing a weaker signature that looks fine. A redaction that cannot guarantee removal refuses rather than leaving the original bytes behind. The expensive outcome — a silently weak signature, a redaction that did not redact — is exactly the one a permissive engine produces by default.
Types as documentation
NextPDF is written in strict, modern PHP and held to PHPStan Level 10 across the codebase. The types are not decoration: they encode what is and is not allowed, so a whole class of “you held it wrong” bugs becomes a compile-time conversation instead of a production incident.
The result is an engine that is, occasionally, less convenient — and far more trustworthy. When the output is a legal document, that is the right way round.