Troubleshooting: signature and timestamp failures
These entries cover signature failures raised through
NextPDF\Exception\SignatureException and
NextPDF\Security\Signature\Exception\SignatureLevelUnreachableException.
Each entry names the exact factory method or class, so you can confirm the
cause from the message and getContext() instead of inferring it.
Wording note: the engine does not certify that a signature is valid or that a document is protected. It reports the failure it detected. Treat each resolution as a step to remove a reported cause.
Entry: PAdES level “B-LT” or “B-LTA” cannot be produced
Section titled “Entry: PAdES level “B-LT” or “B-LTA” cannot be produced”- Symptom.
SignatureExceptionwith the message tailnextpdf/enterprise package is required for B-LT/B-LTA signatures. - Likely cause. The long-term validation capability provider is absent.
B-LT and B-LTA embed revocation material and an archival timestamp, and that
provider ships in
nextpdf/enterprise. - Evidence / diagnosis. The factory
SignatureException::ltvCapabilityMissing()produces this exact message.getContext()returnssignature_levelset to the level you attempted. - Resolution.
- Install the provider by running
composer require nextpdf/enterprise. - Run the sign call again.
- If you cannot install the provider, request
B-BorB-Tinstead, which the core package can produce.
- Install the provider by running
- Related. Exception reference.
Entry: signature level is unreachable and the call is rejected
Section titled “Entry: signature level is unreachable and the call is rejected”- Symptom.
SignatureLevelUnreachableExceptionwith a message in the formPAdES level "<x>" is unreachable (highest achievable: "<y>"). - Likely cause. The requested conformance level needs infrastructure that is not available at sign time, most often a timestamp authority for B-T and above. The engine fails closed: it does not silently downgrade and then advertise the higher level.
- Evidence / diagnosis.
getContext()returnsrequestedLevel,highestAchievableLevel, andreason. Thereasonfield identifies the infrastructure gap. This is the fail-closed default introduced to prevent a document that claims a level it does not meet. - Resolution.
- Read the
reasonfield to identify the missing infrastructure. - Supply the missing component. For example, configure a timestamp authority, and run the call again.
- To intentionally accept a lower level, pass
allowDegradation: truetoPadesOrchestrator. The call then produceshighestAchievableLeveland reports the level it produced.
- Read the
- Related. Encryption and permissions.
Entry: timestamp authority client is required but absent
Section titled “Entry: timestamp authority client is required but absent”- Symptom.
SignatureExceptionwith the tailTSA client is required for level <x> but none was provided. - Likely cause. A B-T, B-LT, or B-LTA request needs a timestamp authority client, and the orchestrator has none.
- Evidence / diagnosis. The factory
SignatureException::tsaRequired()produces this message;getContext()carries the attemptedsignature_level. - Resolution.
- Configure a timestamp authority client and pass it to the orchestrator.
- Re-run the call.
- To produce a level that does not need a timestamp, request
B-B.
- Related. Exception reference.
Entry: timestamp authority endpoint URL is empty
Section titled “Entry: timestamp authority endpoint URL is empty”- Symptom.
SignatureExceptionwith the tailTSA endpoint URL is empty. - Likely cause. A timestamp authority client was created with an empty endpoint URL.
- Evidence / diagnosis. The factory
SignatureException::tsaUrlEmpty()produces this message. This is a configuration defect, not a network failure. - Resolution.
- Set a non-empty endpoint URL on the timestamp authority client, such as
https://timestamp.example.com/tsa. - If the requested level does not require timestamping, remove the timestamp authority client wiring instead.
- Run the call again.
- Set a non-empty endpoint URL on the timestamp authority client, such as
- Related. Exception reference.
Entry: signature placeholder is missing from the buffer
Section titled “Entry: signature placeholder is missing from the buffer”- Symptom.
SignatureExceptionwith the tailno /Contents <…> field found in PDF buffer (signature placeholder missing). - Likely cause. The signing stage received a buffer with no reserved signature container, so it has nowhere to write the signature.
- Evidence / diagnosis. The factory
SignatureException::signatureContentsNotFound()produces this message. - Resolution.
- Make sure the signature field and its placeholder are written before the signing stage runs.
- Run the pipeline again so the placeholder exists when signing starts.
- Related. Exception reference.
Entry: revocation status is unknown (OCSP responder declined)
Section titled “Entry: revocation status is unknown (OCSP responder declined)”- Symptom.
SignatureExceptionwith the tailOCSP responder returned non-successful OCSPResponseStatus "<status>". - Likely cause. The Online Certificate Status Protocol (OCSP) responder
did not return a
successfulstatus, so it produced no revocation assertion. The engine follows RFC 6960 §4.2.1, which it cites in source: a populated response body is permitted only for thesuccessful (0)status. The engine refuses to treat a declined response as a trust-positive result. - Evidence / diagnosis. The factory
SignatureException::nonSuccessfulOcspResponseStatus()produces this message and names the reported status, such astryLaterorinternalError. A reserved or unknown status byte instead producesSignatureException::reservedOcspResponseStatus(). - Resolution.
- Identify the status in the message. For a transient status such as
tryLater, retry the revocation fetch later. - For
unauthorizedormalformedRequest, verify the OCSP request URL and the certificate the responder expects. - Do not suppress the failure to obtain a B-LT or B-LTA artifact; the revocation assertion is part of that level.
- Identify the status in the message. For a transient status such as
- Related. Exception reference.
Entry: certificate chain entry fails to decode
Section titled “Entry: certificate chain entry fails to decode”- Symptom.
SignatureExceptionwith the tailfailed to base64-decode PEM body — input is not valid PEM. - Likely cause. A certificate chain entry is not valid Privacy-Enhanced Mail (PEM), typically because of truncation, a stray character, or a binary Distinguished Encoding Rules (DER) blob supplied where PEM was expected.
- Evidence / diagnosis. The factory
SignatureException::pemDecodingFailed()produces this message during chain assembly. - Resolution.
- Inspect each chain certificate for stray characters or truncation.
- Re-export the affected certificate in PEM form.
- Re-run the sign call.
- Related. Encryption and permissions.
Entry: private key type does not match the algorithm
Section titled “Entry: private key type does not match the algorithm”- Symptom.
SignatureExceptionwith the tailexpected private key of type "<x>" for the configured algorithm but got "<y>". - Likely cause. The loaded private key does not match the configured signature algorithm, such as a Rivest-Shamir-Adleman (RSA) key with an Elliptic Curve Digital Signature Algorithm (ECDSA) selection.
- Evidence / diagnosis. The factory
SignatureException::unexpectedKeyType()produces this message and names both the expected and actual key class. - Resolution.
- Verify that the certificate and key pair match the algorithm you selected.
- Either change the algorithm selection to match the key, or load the key that matches the algorithm.
- Run the sign call again.
- Related. Exception reference.
Entry: Ed25519 key or signature material is malformed
Section titled “Entry: Ed25519 key or signature material is malformed”- Symptom.
SignatureExceptionwith a tail naming an Ed25519 length mismatch — for exampleEd25519 signature length <n> ≠ expected 64 bytes, orEd25519 round-trip self-verify failed. - Likely cause. The runtime cryptography build returned key or signature material of the wrong length, or a freshly produced signature failed verification against its own public key. The engine cites RFC 8032 §3.4 in source, which fixes a detached Ed25519 signature at 64 bytes. The engine aborts instead of emitting material it cannot self-verify.
- Evidence / diagnosis. The relevant factories are
SignatureException::ed25519SignatureMalformed(),::ed25519RoundTripVerifyFailed(),::ed25519KeyParseFailed(),::ed25519SeedInvalid(),::ed25519SecretKeyMalformed(), and::ed25519PublicKeyInvalid(). Each names the observed length. - Resolution.
- Reinstall the libsodium PHP extension; a stripped or corrupt build is the documented cause of wrong-length material.
- Confirm the key is an Ed25519 key and OpenSSL is 1.1.1 or newer.
- Re-run the sign call.
- Related. Exception reference.
Entry: archival timestamp dictionary was not emitted
Section titled “Entry: archival timestamp dictionary was not emitted”- Symptom.
SignatureExceptionwith the tailno /Type /DocTimeStamp dictionary was emitted into the PDF buffer. - Likely cause. The B-LTA archival loop ran, but the document timestamp dictionary never reached the buffer. The artifact would be a half-written B-LTA, so the engine refuses to return it.
- Evidence / diagnosis. The factory
SignatureException::documentTimestampNotEmitted()produces this message. This post-condition failure is raised at finalize time. - Resolution.
- Treat the output as discarded; do not ship the partial artifact.
- Run the B-LTA pipeline again with a reachable timestamp authority.
- If the failure repeats, capture
getContext()and the chained previous exception for a defect report.
- Related. Exception reference.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- These factories set
cert_infoto a subject or thumbprint only when one is available; an emptycert_infois expected for capability and configuration failures. - A B-LT or B-LTA request without a configured Hypertext Transfer Protocol
(HTTP) client raises
SignatureException::httpClientMissing(); the revocation fetch needs a PHP Standards Recommendation (PSR)-18 client passed to the orchestrator. - A certificate backed by a hardware security module (HSM) without a signer
implementation raises
SignatureException::hsmSignerMissing(); wire the signer onto the certificate before signing.
See also
Section titled “See also”Glossary: PAdES level · revocation assertion