Skip to content

Exceptions reference

Module: piighost.exceptions

Every error the library raises derives from PIIGhostError, so one except PIIGhostError covers the whole family. Between the root and the leaves sit the grouping classes, one per subsystem, which a caller catches to react to a stage rather than to a single failure. Every class imports without an optional extra, because the module depends on nothing outside the standard library. That holds for the errors raised by components that need an extra too.

from piighost.exceptions import PIIGhostError

PIIGhostSecurityWarning is the one name in the module outside this tree. Being a warning and not an error, it is described at the end of the page.

The hierarchy

The PIIGhostError tree, each grouping class above the errors it covers.

  • PIIGhostError
    • SpanError
      • NegativeSpanStartError
      • SpanOrderingError
    • DetectionError
      • ConfidenceError
    • EntityError
      • EmptyEntityError
      • MixedLabelError
    • DetectorError
      • LabelMappingError
      • TextTooLongError
      • UnreadableOutputError
      • BridgePayloadError
      • BridgeSpanRangeError
    • TextError
      • EmptyFragmentError
    • AnonymizerError
      • OverlappingSpansError
    • OverrideError
      • ConflictingOverrideError
    • GuardError
      • PIIRemainingError
    • MiddlewareError
      • UnrecognizableFactoryError
      • InventedPlaceholderError
      • MissingThreadIdError
    • HasherError
      • EmptyPepperError
    • CipherError
      • InvalidKeyLengthError
    • ClientError
      • RemoteError
    • ConfigError
      • ConfigFileError
      • ConfigValidationError

Of the thirty-five error classes, twenty-two are raised by a component and thirteen exist only to be caught. ConfigError counts on both sides, because it is a grouping class that is also raised on its own.

Data models

Module: piighost.models. SpanError, DetectionError, and EntityError group the validation failures of the frozen data models. Each is raised from __post_init__, so an invalid value fails at construction and never reaches a stage.

ExceptionRaised byRaised when
NegativeSpanStartErrorSpan.__post_init__start is negative
SpanOrderingErrorSpan.__post_init__end is not strictly greater than start, which describes an empty or a reversed range
ConfidenceErrorDetection.__post_init__confidence falls outside the closed range 0 to 1
EmptyEntityErrorEntity.__post_init__the entity groups no detection
MixedLabelErrorEntity.__post_init__the grouped detections do not all share one label

The invariants these errors enforce are in Data models, and the ports that exchange the models in Extending piighost.

Detectors

Module: piighost.components.detector.ner. DetectorError groups five failures. Two belong to BaseNERDetector, so they reach the model-backed detectors only. One belongs to LLMDetector, and so to LLMGuardRail too. The last two belong to BridgeDetector, which checks every span its runner returns rather than trusting it. A regex, exact-match, composite, or chunked detector raises none of them.

ExceptionRaised byRaised when
LabelMappingErrorBaseNERDetector.__init__two external labels map to one internal label, which would make the reverse lookup ambiguous
TextTooLongErrorBaseNERDetector, on detectiona text exceeds max_chars while auto_chunk is off, rather than scanning only the start of the text
UnreadableOutputErrorLLMDetector, on detectionthe model returns an output the detector cannot read, a broken JSON or a result without its entities field, while fail_open is off
BridgePayloadErrorBridgeDetector, on detectionthe runner returns a span missing a field, or an offset that is not an integer. A float is refused too
BridgeSpanRangeErrorBridgeDetector, on detectionthe runner returns an empty or inverted span, one that overruns the text, or, in UTF-16 units, one that cuts a character in two

All five are covered in Detectors, with the max_chars and auto_chunk arguments that govern TextTooLongError, the fail_open argument that governs UnreadableOutputError, and the offset_unit that the bridge's offsets are read in.

Text helpers

Module: piighost.text. TextError groups the failures of the word-boundary helpers and carries one subclass.

ExceptionRaised byRaised when
EmptyFragmentErrorboundary_wrap, find_all_word_boundary, and ExactMatchDetector.__init__the fragment searched for is empty, which would match at every position of the text

Without this error, an empty fragment would yield zero-width spans, which a Span refuses. The failure would then surface as a SpanOrderingError, far from its cause. ExactMatchDetector checks its configured values at construction, so a config typo fails at load rather than on the first message. LLMDetector does not raise it, because a model's output is untrusted. It drops a blank extracted value with a warning instead.

Anonymizer

Module: piighost.components.anonymizer. AnonymizerError groups the render stage's failures and carries one subclass.

ExceptionRaised byRaised when
OverlappingSpansErrorAnonymizer.rendertwo spans still overlap when the one-pass rewrite reaches them

The disjoint-span assumption behind it is in Anonymizer, and the stage that upholds it in Pipeline.

Detection overrides

Module: piighost.components.override. OverrideError groups the failures of the deny list and allow list stage and carries one subclass.

ExceptionRaised byRaised when
ConflictingOverrideErrorDetectionOverride.applya span on the deny list overlaps one on the allow list under the raise conflict strategy

The other two conflict strategies resolve the collision instead of raising. Every [override] key is in the configuration reference.

Guard rails

Module: piighost.pipeline. GuardError groups the guard-stage failures and carries one subclass.

ExceptionRaised byRaised when
PIIRemainingErrorthe pipeline, after the guard stagea guard returns a flagged verdict

A guard raises nothing itself. It returns a verdict, and the pipeline turns a flagged one into this error, as described in Guard rails.

Integrations

Module: piighost.integrations. MiddlewareError groups the failures of the integration layer. The first two below come from the shared TextDeidentifier, which backs the LangChain middleware, the LlamaIndex query engine, and the Pydantic AI hooks alike. The third belongs to the LangChain middleware alone.

ExceptionRaised byRaised when
UnrecognizableFactoryErrorTextDeidentifier.__init__the pipeline exposes no token recognizer, because its placeholder factory has no re-findable grammar
InventedPlaceholderErrorTextDeidentifier.deanonymize and deanonymize_streamrestored text still holds a token the pipeline never issued, under the RAISE invented-placeholder strategy
MissingThreadIdErrorthe LangChain middleware and the Claude Code hooks, on each turnthe LangGraph config carries no thread_id, or the hook event no session_id

The three are covered in LangChain integration, with the strategies that decide whether the second is raised at all.

Crypto

Module: piighost.crypto. HasherError and CipherError group the constructor failures of the at-rest primitives, one subclass each.

ExceptionRaised byRaised when
EmptyPepperErrorBaseHasher.__init__the pepper is empty, which would leave low-entropy PII brute-forceable
InvalidKeyLengthErrorAesGcmCipher.__init__the AES key is not 16, 24, or 32 bytes

Both fail closed at construction, so a misconfigured store never starts. What these primitives protect is in Security, and the memory backends that take them in Conversation memory.

Remote client

Module: piighost.integrations.client. ClientError groups the remote client's failures and carries one subclass.

ExceptionRaised byRaised when
RemoteErrorPIIGhostClient, on every callthe remote piighost-api answers with a non-2xx status

The status guard is all it covers. A 2xx body missing an expected key surfaces as a KeyError, not a RemoteError. The client's methods are in API client.

Configuration

Module: piighost.config. ConfigError groups the load-time and build-time failures. Unlike the other grouping classes, it is also raised on its own.

ExceptionRaised byRaised when
ConfigFileErrorload_configthe file is missing, unreadable, or invalid TOML or JSON, or a catalog reference answers something that is not TOML
ConfigValidationErrorload_configthe parsed data fails schema validation. The error then wraps pydantic's ValidationError in the library's family
ConfigErrorload_pipeline, load_thread_pipeline, and a component config's build()the entry point does not match the [memory] section declared, a secret environment variable is unset or malformed, or a memory declares exactly one of a hasher and a cipher

Catching ConfigError covers all three. Every key and every secret variable is in the configuration reference, and the piighost CLI reports the same three from validate, as described in CLI.

Errors carrying data

Three errors expose the values behind the failure as attributes. Every other error carries its message only.

ExceptionAttributeHolds
PIIRemainingErrordetectionsthe residual detections behind the flag, empty when the guard is score-based and localizes nothing
InventedPlaceholderErrortokensthe invented tokens, in order of appearance
RemoteErrorstatus_codethe HTTP status the server returned

PIIGhostSecurityWarning

PIIGhostSecurityWarning is a UserWarning, outside the PIIGhostError tree. So it never fails a call, and the standard warnings filters govern it. It marks a setup that runs but keeps confidential data readable. Because it is only a warning, a knowing choice still works, and a forgotten one stays loud. Two sites emit it, both at construction.

Emitted byEmitted when
warn_plaintext, called from RedisConversationMemory and SqlAlchemyConversationMemorya persistent backend is built without a hasher and a cipher, so its store holds confidential data in clear
BaseAnonymizationPipeline.__init__no observation_redactor is set, trace_clear_text is off, and the tracer is exporting, so traces would record clear text

The backend comparison is in Conversation memory, and the redactor in Observation.

See also