Errors
This content is for v0.5.0. Switch to the latest version for up-to-date documentation.
Paxman uses two different signals for “something went wrong”: statuses for domain answers and exceptions for setup, caller misuse, and pipeline failures. Knowing which is which keeps your code and notebooks simple.
Statuses vs exceptions
Section titled “Statuses vs exceptions”- A status (
MISSING,INVALID,AMBIGUOUS,SUCCESS) is a normal domain answer. It means the pipeline ran, considered the input, and has a well-defined conclusion — even when that conclusion is “there is no valid answer.” Handle it by branching onresult.status. - A setup or caller-misuse exception (
ContractError,CapabilityErroron late registration,MultipleMentionsErrorfor unsegmented input) means the call was not valid in the first place. A frozen registry is valid for ordinarycanonicalize()calls — it only raisesCapabilityErrorif you try to register after freezing. - A pipeline-failure exception (
RecognitionError,ValidationError) means a grammar or rule failed unexpectedly. These are distinct from statuses and signal a bug to report, not a domain answer. MultipleMentionsErroris raised after the pipeline inspected the input and found two non-overlapping mentions with different values — it is a deliberate fail-fast for unsegmented input, not a case where Paxman could not inspect the input.
Rule of thumb: check status in normal code; catch exceptions only around setup and at the outer boundary of a batch.
The exception hierarchy
Section titled “The exception hierarchy”All Paxman exceptions inherit from PaxmanError.
| Exception | When it is raised | What to do |
|---|---|---|
CapabilityError | Unknown capability name, duplicate capability/grammar name, or registering after the registry has frozen | Register before the first canonicalize(); check spelling; avoid duplicate names |
ContractError | Malformed contract — unknown pinned_rules entry, unknown output_format, unknown semantics in extra_grammars, or a rule’s required feature missing from the contract | Fix the contract — see Contracts |
MultipleMentionsError | One call contained two or more separate mentions that resolved to different values — un-segmented multi-entity input | Split the input first — see the Segmentation Recipe |
RecognitionError | A grammar failed structurally (exception inside recognize()) or returned a malformed match (bad span or raw_text) | Treat as a bug in a grammar (shipped or community); carries rule and original_error |
ValidationError | A rule raised unexpectedly inside matches() / normalize() | Treat as a bug in a rule; carries rule and original_error |
RecognitionErrorandValidationErrorcarryrule(the grammar/rule name) and render as"[rule] message". On structural recognition failuresoriginal_errorisNone; on internal failures it is the underlying exception.
Typical handling
Section titled “Typical handling”Setup — fail fast
Section titled “Setup — fail fast”import paxmanfrom paxman.capabilities import Emailfrom paxman.core.errors import CapabilityError, ContractError
try: paxman.register_all_shipped() contract = Email.create_contract(output_format="typo") # not offeredexcept ContractError as e: print(f"Bad contract: {e}")except CapabilityError as e: print(f"Registration problem: {e}")An unknown output_format always raises ContractError immediately — never a silent fallback.
Canonicalization loop — branch on status
Section titled “Canonicalization loop — branch on status”from paxman.core.domain import Resolution
result = paxman.canonicalize("Contact user@Example.com", contract)
if result.status == Resolution.SUCCESS: use(result.canonicalized_value)elif result.status in (Resolution.MISSING, Resolution.INVALID): # domain answer — skip or flag, no exception to catch log(result.status, result.candidates)elif result.status == Resolution.AMBIGUOUS: surface(result.candidates) # see Candidates & AmbiguityBatch with segmentation — handle MultipleMentionsError
Section titled “Batch with segmentation — handle MultipleMentionsError”from paxman.core.errors import MultipleMentionsError
try: result = paxman.canonicalize("alice@example.com and bob@example.org", contract)except MultipleMentionsError as e: # Input contained two different mentions — split before retrying. # See the Segmentation Recipe for the loop pattern. print(f"Need to segment: {e}")Narrow RecognitionError / ValidationError
Section titled “Narrow RecognitionError / ValidationError”These indicate a bug in a grammar or rule (shipped or community). Catch them at the outer boundary; do not treat them as domain statuses.
from paxman.core.errors import RecognitionError, ValidationError
try: result = paxman.canonicalize(text, contract)except (RecognitionError, ValidationError) as e: print(f"[{e.rule}] pipeline bug: {e} — original: {e.original_error}")In plain language
Section titled “In plain language”Statuses are the library saying I looked, and here is what the specs say — even when the answer is “nothing there” or “two specs disagree.” Exceptions are the library saying the request was not valid (wrong setup or contract), a pipeline step failed (grammar/rule bug), or you gave me two different things in one slot (unsegmented input inspected before failing). Handle statuses in your normal flow; handle exceptions as setup/misuse/bug signals.
Where to go from here
Section titled “Where to go from here”- Getting Started — register and call correctly the first time
- Concepts — Overview — rebuild the full mental model
- Segmentation Recipe — the correct way to handle text with multiple entities