Error Handling
Branch on typed error kinds — mudrit_pdfsign::Error and mudrit_keystore::Error — for precise retry UX
Both crates return typed error enums so callers branch on the kind of failure rather than
scraping a message string. Both are #[non_exhaustive] — new variants can be added without a
breaking change — so every match must include a _ => arm.
Signing errors — mudrit_pdfsign::Error
Categorised by failure kind. Key-source failures preserve the underlying mudrit_keystore::Error.
| Variant | Meaning |
|---|---|
Io(String) | File or stream I/O (reading the input, writing the output) |
InvalidInput(String) | Bad configuration or PDF input — no placements resolved, page selector out of range, SigSize too small, a missing/oversized field |
Encryption(String) | Encryption / decryption — wrong or absent open password, unsupported cipher, key derivation |
Network(String) | A network fetch failed — timestamp authority, CRL, or OCSP responder |
Signing(String) | CMS / PKCS#7 assembly, certificate parsing, or the signature itself |
Pdf(String) | PDF structure — parsing, building, or serialising the document |
Keystore(mudrit_keystore::Error) | A key-management failure, preserved with its original type |
LtvIncomplete(String) | LtvPolicy::Require was set but no CRL / OCSP could be obtained; the message lists the actionable fixes |
use mudrit_pdfsign::{sign_pdf, Error};
match sign_pdf(&pdf, &signer, &cfg) {
Ok(out) => std::fs::write("out.pdf", out)?,
Err(Error::Network(m)) => eprintln!("retryable — TSA/CRL/OCSP fetch failed: {m}"),
Err(Error::InvalidInput(m)) => eprintln!("fix the config or input: {m}"),
Err(Error::Keystore(k)) => handle_key_error(&k), // inspect the typed key error
Err(e) => eprintln!("signing failed: {e}"), // _ arm — required
}Key errors are preserved, not flattened
When a signature fails because of the key source, the original mudrit_keystore::Error (e.g.
WrongPin, PinLocked) is carried inside Error::Keystore, and is also reachable via
std::error::Error::source. Match on it to drive the same retry UX described below.
Key-management errors — mudrit_keystore::Error
| Variant | Meaning |
|---|---|
Cancelled | The user dismissed a certificate-selection dialog |
TokenNotFound | No PKCS#11 token / smart card in any slot |
NotFound(String) | The requested certificate, alias, or key was not found |
WrongPassword | A PFX/P12 password was wrong (or failed its integrity / MAC check) |
Authentication(String) | Authentication failed — e.g. a wrong token PIN |
WrongPin { final_try, count_low } | A wrong token PIN; final_try = last attempt before lock, count_low = only a few attempts remain |
PinLocked | The token's user PIN is locked — unlock it on the device |
KeyUnusable(String) | A certificate's private key is missing or unusable |
UnsupportedKey(String) | The key type / signature scheme is not supported (e.g. a device returned a signature that does not verify as the requested algorithm) |
Unsupported(String) | The operation is unavailable on this platform (e.g. the Windows store off Windows) |
Io { message, source } | A filesystem / I/O error; source preserves the original std::io::Error |
Backend(String) | Any other backend / OS / cryptographic-library error |
Retry UX — branch the PIN state
PKCS#11 exposes PIN state as flags, not an exact remaining count, so WrongPin carries
final_try and count_low. Branch them to drive an amber / red / locked prompt:
use mudrit_keystore::Error;
fn on_unlock_error(e: &Error) {
match e {
Error::WrongPin { final_try: true, .. } => show_red("Wrong PIN — LAST attempt before lock"),
Error::WrongPin { count_low: true, .. } => show_amber("Wrong PIN — only a few attempts remain"),
Error::WrongPin { .. } => show_amber("Wrong PIN — try again"),
Error::PinLocked => show_locked("PIN locked — unlock it on the device"),
Error::WrongPassword => show_red("Wrong PFX password"),
Error::Cancelled => { /* user dismissed — no error UI */ }
_ => show_red(&e.to_string()), // _ arm — required
}
}Match with a wildcard arm
Both enums are #[non_exhaustive]. A match without a _ => arm will not compile against a future
version of the crate — always include one so new variants degrade gracefully to a generic message.
Next
PDF/A Assertion
Assert PDF/A-2B conformance on the signed output — sRGB OutputIntent, pdfaid XMP, and a document /ID
Troubleshooting & FAQ
Symptom, cause, and fix for the errors you are most likely to hit — wrong passwords and PINs, untrusted certificates, PSS on tokens, LTV, sizing, and appearance fonts.