Error Message Catalog
This catalog covers HTTP error responses and domain-specific exceptions returned by the Raw to Knowledge API. For each error, it identifies when it occurs, the most likely cause, and how to resolve it.
Note: Detailed error context is always present in the response body's
detailfield and in the service's structlog output. When investigating an unexpected error, check both sources.
HTTP errors
4xx client errors
| Status | When seen | Common cause | Resolution |
|---|---|---|---|
400 Bad Request |
Any POST endpoint | Malformed JSON in the request body, or a required field is missing from the request. Pydantic could not parse the payload at all. | Validate your JSON syntax. Check the request body against the schema in /docs. Ensure all required fields are present. |
404 Not Found |
GET /{id}, POST /{id}/action |
The specified ID does not exist in the database, or the resource exists but is not in a status that permits this operation (e.g., requesting export of a RETIRED answer). |
Confirm the ID using a list endpoint. Check the current status or state of the resource. |
409 Conflict |
POST /v1/artifacts |
The source_ref field in the request matches an artifact that has already been ingested. |
Use a unique source_ref. Retrieve the existing artifact using GET /v1/artifacts if you need to reference the original ingest. |
422 Unprocessable Entity |
Any POST with a request body | Pydantic field-level validation failure (wrong type, value out of range, required field null), or a domain rule violation such as an invalid state transition, missing provenance, or a disallowed operation. The detail field in the response body contains the specific field and error message. |
Read the detail field carefully. Check field types and required fields in /docs. For domain violations, see the domain exceptions section below. |
5xx server errors
| Status | When seen | Common cause | Resolution |
|---|---|---|---|
500 Internal Server Error |
Any endpoint | An unhandled exception in the service. Common causes: database connection failure, unexpected null value, unhandled edge case in domain logic. | Check the structlog output for the full stack trace. Verify that PostgreSQL and Redis are reachable. If the error is intermittent, check for resource exhaustion (connections, memory). |
503 Service Unavailable |
Generation endpoints, graph endpoints | A downstream service is unavailable — most commonly, the LLM circuit breaker has opened (CircuitOpenError). |
See CircuitOpenError in the domain exceptions section below. For graph endpoints, check Neo4j availability. |
Domain exceptions
Domain exceptions are raised by Raw to Knowledge's application layer when a business rule is violated. They are returned as 422 Unprocessable Entity or 503 Service Unavailable responses with a descriptive detail field.
| Exception | HTTP status | Meaning | What triggers it |
|---|---|---|---|
ProvenanceError |
422 |
A registry publish attempt is missing one or more required provenance fields: validation_record_id, owner_role, or evidence_links. |
POST /v1/registry/answers without all three provenance fields present and non-empty. |
ValidationStateError |
422 |
An illegal state machine transition was attempted on a CandidateAnswer. The requested transition does not exist in the permitted transition table. |
Attempting to approve a REJECTED candidate, claim an already-IN_REVIEW candidate, or any other transition not permitted from the current state. See States, Statuses, and Queues. |
UnvalidatedRegistryWriteError |
422 |
A registry publish was attempted, but the referenced ValidationRecord does not have decision = APPROVED or REVISED. |
POST /v1/registry/answers with a validation_record_id that points to a record with decision = REJECTED, ESCALATED, or any non-approving decision. |
CircuitOpenError |
503 |
The LLM circuit breaker has tripped. The circuit opened after 5 consecutive LLM failures within a 60-second window. All LLM calls are being rejected without attempting the API. | Automatic on the 6th consecutive failure after the circuit opens. The breaker recovers automatically after 60 seconds, or on worker restart. |
Reading the detail field
All 422 and 500 responses include a detail field in the response body. For Pydantic validation errors, this is an array of objects:
{
"detail": [
{
"loc": ["body", "evidence_links"],
"msg": "field required",
"type": "missing"
}
]
}
For domain exceptions, detail is a string:
{
"detail": "ValidationStateError: Transition REJECTED → APPROVED is not permitted"
}
The structlog output from the API service includes the same information plus the full Python stack trace, request ID, and timestamp. Use log output when the detail field alone is not sufficient to diagnose the issue.
Common error patterns
Getting many 422 errors on POST requests:
- Run a test request against the /docs Swagger UI, which validates the schema client-side before sending.
- Compare your request body structure against the Pydantic model shown in the /docs schema section.
- For enum fields, use exact enum values. Enum values are case-sensitive.
Getting 500 on a previously working endpoint:
- Check GET /health — if "db": "error", the database is unreachable.
- Check for recent migration changes: alembic current should match the expected revision (005).
- Restart the API service if a transient resource issue is suspected.
Getting 404 on an ID you just created:
- Confirm the ID from the creation response was copied correctly.
- Check whether the resource is in a status that the endpoint requires (e.g., readout requires APPROVED).
- Confirm the endpoint path matches the resource type (answer IDs and candidate IDs are different namespaces).