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.