Errors
Every HankoXml error descends from HankoXml::Error — rescue that to catch anything the library
raises. Errors carry structured context, not just a message.
StandardError
└── HankoXml::Error base; rescue this to catch everything
├── HankoXml::ConfigurationError invalid Signer/Verifier construction
│ ├── HankoXml::PolicyError a Policy allowlist was violated
│ ├── HankoXml::PlacementError placement XPath matched 0 or >1 nodes
│ ├── HankoXml::NokogiriRequired this capability needs a DOM
│ └── HankoXml::SchemaError <Signature> failed XSD validation
├── HankoXml::ParseError the XML would not parse
├── HankoXml::KeyLoadError key or certificate unreadable / unsupported
├── HankoXml::ReferenceError a reference target does not exist, is
│ ambiguous, or has no ID attribute
├── HankoXml::SigningError libxmlsec1 could not produce a signature
├── HankoXml::VerificationError verification did not succeed (raised by verify!)
│ ├── HankoXml::SignatureInvalid cryptographic mismatch
│ ├── HankoXml::SignatureMissing no <ds:Signature> in the document
│ ├── HankoXml::MultipleSignatures signature: :only and >1 present
│ ├── HankoXml::UntrustedCertificate chain/pinning failed
│ ├── HankoXml::CertificateExpired outside notBefore/notAfter, as of
│ │ verification_time
│ ├── HankoXml::DigestMismatch one <Reference>'s digest is wrong;
│ │ carries #reference_uri
│ ├── HankoXml::ResolutionMismatch resolver vs xmlsec disagree
│ └── HankoXml::XadesError a XAdES check failed: signed
│ properties, a timestamp, LT data
├── HankoXml::NotSignedError Verification#at_signed found a node that
│ the signature does not cover
├── HankoXml::FrozenSignatureError a mutator was called on a
│ SignedDocument
└── HankoXml::NativeError libxmlsec1 failed in an unexpected way
└── HankoXml::NativeVersionMismatch the loaded libxmlsec1/libxml2 do not
match the build (raised at require)
Note the name is
HankoXml::KeyLoadError, notKeyError— deliberately avoiding a name that shadows a Ruby core class.
Structured context
begin
HankoXml.verify!(xml, certificate: cert)
rescue HankoXml::Error => e
e.xmlsec_errors # => ["func=xmlSecOpenSSLEvpSignatureVerify:file=signatures.c:
# line=444:obj=rsa-sha256:subj=EVP_VerifyFinal:error=18:
# data do not match"]
e.signature_node # => Nokogiri::XML::Element, when one was located
e.reference_uri # => "#infNFe01", on ReferenceError
end
#xmlsec_errors is captured by installing an xmlSecErrorsSetCallback handler that appends into a
thread-local buffer, drained on each native call. This is the difference between
SigningError: failed to sign and an actual diagnosis.
#message is always a fixed string from HankoXml, and the exception class depends on where the
failure happened, never on the log’s wording. The xmlsec log can quote text from the document
(algorithm URIs, Reference URIs, node names), so it appears only in #xmlsec_errors. Treat that
array as untrusted input before logging or displaying it.
HankoXml::Error and subclasses never carry key material. The error constructor filters any
value that came from a Key.
Per-reference errors
DigestMismatch and similar failures carry #reference_uri because “the digest of reference 2 does
not match” and “the signature over <SignedInfo> does not match” are completely different bugs —
the first means the data changed, the second means the key or the canonicalization is wrong. See
Verification::Reference for the per-reference #errors
accessor.