Error reference
Status: draft. Local error mapping is separate from live-service evidence. Only the recorded calls establish what the service returned; see the evidence ledger.
Common error base
JudgevetError is the neutral base for declared library errors.
Import it from judgevet, judgevet.domain or judgevet.domain.errors.
All three paths expose the same class. It inherits from Exception and uses
ordinary exception arguments. It adds no status or retry metadata.
except JudgevetError catches both Jev errors and local policy errors.
Ordinary Python validation errors and arbitrary provider exceptions keep their
existing types and do not become JudgevetError instances.
Source: https://github.com/Alberto-Codes/judgevet/issues/78#issuecomment-5850346340.
Error hierarchy
Declared provider failures share one spine:
JudgevetError → ProviderError → JevError → each Jev* error.
ProviderError is the base the conformance kit
requires from a failing port. A hosted Jev failure is a JevError, so it also
satisfies ProviderError. except ProviderError catches Jev errors and the
six neutral provider errors. A neutral provider error is not a JevError.
ProviderBusyError is a ProviderUnavailableError: the provider is up, but
another model or caller holds the backend, and no judgment ran.
Source: https://github.com/Alberto-Codes/typevet/issues/461.
Local policy errors derive from JudgevetError, not from ProviderError.
Source: https://github.com/Alberto-Codes/judgevet/issues/259#issuecomment-5910551186.
Service and transport errors
The supported names are exported from judgevet. Each concrete error below
inherits directly from JevError, which inherits from ProviderError. The one
exception is JevMaxTokensExceededError, which inherits from JevRequestError.
JevBudgetExceededError is a local refusal, not a service outcome.
JevRateLimitError is not a subclass of JevRequestError or JevServiceError.
| Type | Constructor | HTTP adapter mapping | retryable |
|---|---|---|---|
JevError |
JevError(message, status_code=None) |
Base type; not a catch-all for every failure | False |
JevAuthError |
JevAuthError(message, status_code) |
401 or 403 | False |
JevRequestError |
JevRequestError(message, status_code) |
Other 400–499 statuses, excluding 429 | False |
JevMaxTokensExceededError |
JevMaxTokensExceededError(message, status_code) |
A 400–499 body whose detail.error_type is max_tokens_exceeded |
False |
JevRateLimitError |
JevRateLimitError(message, status_code) |
429 | True |
JevServiceError |
JevServiceError(message, status_code=None) |
500–599, or HTTPX2 RequestError such as a timeout |
True |
JevResponseError |
JevResponseError(message, status_code) |
Successful 200–299 answer that cannot be parsed | False |
JevBudgetExceededError |
JevBudgetExceededError(limit, cap, spent) |
No HTTP status; an opt-in SpendCap refused the attempt before sending |
False |
This table describes the adapter mapping and error classes. It does not assert that every status has been observed. The vendor API reference is the source for documented service errors. Live 400, 401 and 422 bodies have been observed; 429 and 529 bodies remain unseen. Other mapped statuses are local compatibility behavior, not additional verified service outcomes.
Concrete constructors validate the status range and raise ValueError for an
invalid code. JevRequestError permits 400–499 except 401/403 when constructed
directly, including 429; the HTTP adapter nevertheless maps 429 to
JevRateLimitError. JevServiceError permits None for transport failures.
JevError itself does not validate the status or infer retryability from it.
Oversized requests
One call with a 400,000-character state returned status 400 and the body
{"detail": {"error_type": "max_tokens_exceeded"}}.
Source: https://github.com/Alberto-Codes/judgevet/issues/39#issuecomment-5825759575.
The adapter raises JevMaxTokensExceededError for that marker on any 4xx
status. It matches the marker, not the status, because one call has seen the
status. The error has retryable=False, because the same request fails again.
except JevRequestError still catches it. The body does not say which token
budget the request exceeded. The vendor states a 64k-token request budget and a
32k-token budget for state plus the longest question.
Source: https://docs.typesafe.ai/models.md.
See service limits.
Spend cap refusals
An adapter given spend_cap=SpendCap(...) raises JevBudgetExceededError
before an attempt when a limit is already reached. No request is sent, so
status_code is None. The error carries limit ("attempts" or
"input_tokens"), cap and spent. Its constructor raises ValueError for
any other limit name. It is not retryable, because the cap never resets.
See spend cap.
All Jev errors expose status_code and the retryable property. The message is in
standard exception args, not a .message attribute. str(error) appends
(status N) when a status is present. Messages can include remote content;
do not assume they are safe to publish.
The following complete example runs offline and prints nothing when its assertions pass. It demonstrates metadata only; it makes no service call.
from judgevet import JevError, JevRateLimitError, JevServiceError
base = JevError("Synthetic base error", 500)
assert base.retryable is False
rate_limit = JevRateLimitError("Synthetic rate limit", 429)
assert rate_limit.retryable is True
transport = JevServiceError("Synthetic transport failure")
assert transport.status_code is None
assert transport.retryable is True
Retry and exception boundaries
retryable is advisory metadata. Callers can enable the adapter's
bounded retry policy. The default is three attempts; see
the retry module.
The adapter does not honor Retry-After headers. A read timeout does not prove the service stopped processing.
The adapters wrap non-success HTTP statuses in JevError subclasses and retain
httpx2.HTTPStatusError as the cause. Redirects stay disabled; a redirect status
raises the generic JevError. This mapping has synthetic test evidence and does
not establish that the live service returns redirects.
Source: https://pydantic.dev/docs/httpx2/api/exceptions/.
except JevError does not catch every Python exception. Missing constructor keys,
invalid arguments, serialization failures and application errors can raise other
types. Keep those visible without publishing an arbitrary traceback. See the
handling recipe.
Invalid answer values in a successful service response raise JevResponseError
through both HTTP adapters. The shared parser translates TypeError and
ValueError from answer parsing and construction. These errors have
retryable=False; enabling retries does not repeat the request. New validation
messages identify the answer type and a bounded question identifier. They omit
answer values and suppress the original validation exception display. Direct
answer construction retains Python TypeError and ValueError semantics.
See the answer contract and
parser source.
Error content
The adapter extracts selected information from service detail values. For
validation lists it omits the input field. That omission is not universal
redaction of remote text, URLs or credentials. The observed 401 body contains an
object and the observed 422 body contains a list; neither shape establishes the
unseen 429/529 bodies. See diagnostic limits.
A body without detail may carry {"error": "<string>"}, the shape Ollama
documents. The adapter then appends a nonempty error string to the message.
The status code still selects the exception type. No call here has observed
this body. See _read_error_detail in src/judgevet/adapters/outbound/response_translation.py.
Source: https://docs.ollama.com/api/systemone.
Local policy errors
Import these from judgevet.policy, not the package root:
| Type | Parent | Meaning |
|---|---|---|
PolicyError |
JudgevetError, ValueError |
Base for local policy failures. |
PolicyDefinitionError |
PolicyError |
Invalid rule, policy JSON or question binding. |
PolicyAnswerError |
PolicyError |
A selected answer is missing, has the wrong type or violates required answer constraints. |
These errors have ordinary exception arguments and no status_code or
retryable contract. They do not inherit from JevError. A valid evaluation
with passed=False is an unmet policy, not a PolicyAnswerError.
The Python policy guide
explains handling and the compatibility reference distinguishes
strict public evaluation from the legacy CLI checks.
Adapter presentation
The CLI renders handled input/service failures on stderr and exits 1. With
--json, those handled errors use an error string member; framework usage
errors retain their own presentation and exit 2. Startup and unexpected failures
are outside that envelope. A valid unmet policy exits 3 with answers on stdout.
See the CLI policy guide.
MCP call failures are distinct from a negative judgment. Tool handlers can raise for bad arguments, missing/wrong-type answers or service failures; the MCP runtime handles their protocol presentation. The entry point reports missing runtime, invalid settings or missing credentials with status 2. It returns 130 on keyboard interruption and reports handled startup/runtime exceptions with a fixed diagnostic. See MCP connection checks.