Errors
jes raises a small family of exceptions, all under JesError, for problems
in your setup or in the backend. Problems in the text never raise.
Its job
The errors draw one line: your code versus the text you check.
- If the setup is wrong, jes raises: a missing threshold, a judgment with no model, a broken custom policy. You fix the code. Most of these fire when you build the guard, before any traffic.
- If the text is a problem, jes returns a result with a finding: too long,
invalid Unicode, an injection, too many redactions. Your code branches on
result.ok, as it does for every other check. - The backend sits in between. A timeout or a 429 isn't your bug, and it
isn't the text's fault. You choose how it surfaces with
on_backend_error.
Mental model
JesError
├── ConfigError agent hooks: bad config file, payload, or env
├── PolicyError bad setup, raised when you build things
├── PolicyExecutionError a custom policy broke its contract mid-check
├── RedactionError wrong store, bad scope, blob won't load
└── BackendError the model call failed (reason says why)
└── DeadlineExceeded the check ran past deadline_s
Messages carry metadata only, never the checked text or a provider's response body. Every jes error is safe to log.
Using it
Setup errors surface right away. Build guards at startup, so they fail before traffic:
from jes import Guard, PolicyError
from jes.policies import injection
try:
guard = Guard([injection(threshold=0.72)]) # no model=
except PolicyError as error:
print(error) # judgment injection has no model; pass model= to the guard
Backend errors depend on on_backend_error:
on_backend_error | A failed model call | ok |
|---|---|---|
"raise" (default) | The check raises BackendError | n/a |
"block" | A blocking backend_error finding | False |
"allow" | A flag backend_error finding | False |
With "block" or "allow" the result is incomplete, so ok is false
either way. "allow" only matters if you act on decision instead of ok.
With the default, catch BackendError where you call the check:
from jes import BackendError
try:
result = guard.check_input(user_text)
except BackendError as error:
log.warning("jes backend failed: %s %s", error.backend, error.reason)
return refuse()
Good to know
- Don't catch
PolicyErrororPolicyExecutionErrorper request. They mean the code is wrong.PolicyExecutionErroralways raises, whateveron_backend_errorsays. - A missing
threshold=is aTypeError. The factories make it a required keyword, so Python rejects the call before jes runs. error.reasonis a stable string, such astimeout,rate_limited,unauthorized, ordeadline_exceeded. Branch on it for retries. The full list is in the reference.except JesErrorcatches everything jes raises, for a single catch-all at a boundary.- The Python library never raises
ConfigError. Only the agent hooks do.
Next
- Errors reference: every class and reason.
- Failures and limits: backend errors, deadlines, and the findings that replace exceptions.
- Result:
ok,decision, andcomplete.