Released docs. You are viewing the documentation published with v0.20.0. Development docs are available at Latest.
Each of the three services answers a failing request with a fixed, value-free body. None of them attaches the rejected value, the SQL it would have run, a source path, token material, or a principal identifier to the failure. This page carries Relay’s set in full and points at the two sets that are written down elsewhere under their own drift gates.
Relay returns errors as RFC 9457 problem details with the media type application/problem+json.
The set is closed: ProblemCode in crates/registry-relay-v2/src/problem.rs has 26 variants and
the HTTP boundary can return nothing else.
Response shape
Section titled “Response shape”Every problem body carries exactly six members, and no operation adds a seventh.
| Member | Value |
|---|---|
type | https://id.registrystack.org/problems/registry-relay/<code with dots replaced by slashes> |
title | The fixed title for the code |
status | The HTTP status, repeated in the response status line |
detail | The fixed detail sentence for the code |
code | The stable code string |
traceId | The 32-character W3C Trace Context trace identifier for this request |
Every problem response also carries Content-Type: application/problem+json and
Cache-Control: no-store. The two 401 codes add WWW-Authenticate: Bearer realm="registry-relay".
The two 429 codes add Retry-After: 60.
Branch on code and status. Do not parse the type URI path: it exists to identify and document
the problem type.
traceId comes from the request’s traceparent header when that header parses, and from a
server-created context when it does not. Relay always removes a caller-supplied tracestate and
never reflects it, so vendor state cannot round-trip through the error boundary.
Problem codes
Section titled “Problem codes”Unlike a taxonomy that varies its status by operation, each Relay code maps to exactly one status.
| Code | Status | Title | Detail |
|---|---|---|---|
consultation.invalid_request | 400 | Consultation request is invalid | the consultation request is invalid |
aggregate-data.invalid_request | 400 | Aggregate data request is invalid | the aggregate data request is invalid |
request.fields_invalid | 400 | Field selection is invalid | field selection is invalid |
filter.unknown_field | 400 | Filter is not declared | filter is not declared for this operation |
filter.invalid_value | 400 | Filter value is invalid | filter value is invalid |
query.cursor_invalid | 400 | Cursor is invalid | cursor is invalid for this query |
request.access_profile_invalid | 400 | Access profile selection is invalid | access profile selection is invalid |
auth.missing_credential | 401 | Bearer access token is required | a bearer access token is required |
auth.invalid_credential | 401 | Bearer access token is invalid | bearer access token validation failed |
consultation.denied | 403 | Consultation is not permitted | the consultation is not permitted |
aggregate-data.denied | 403 | Aggregate data access is not permitted | aggregate data access is not permitted |
resource.not_found | 404 | Requested resource was not found | the requested resource was not found |
consultation.unresolved | 404 | Requested record was not resolved | the requested record was not resolved |
format.unsupported | 406 | Requested format is not supported | the requested format is not supported |
internal.payload_too_large | 413 | Request body is too large | request body exceeds the configured limit |
consultation.response_too_large | 413 | Consultation response is too large | the consultation response exceeds the configured limit |
aggregate-data.too_large | 413 | Aggregate data request is too broad | the aggregate data request exceeds its observation limit |
internal.uri_too_long | 414 | Request URI is too long | request URI exceeds the configured limit |
request.media_type_unsupported | 415 | Request media type is not supported | request body must use application/json |
consultation.rate_limited | 429 | Consultation quota is exhausted | the consultation quota is exhausted |
aggregate-data.rate_limited | 429 | Aggregate data quota is exhausted | the aggregate data quota is exhausted |
internal.unhandled | 500 | Request could not be served | the request could not be served |
source.unavailable | 503 | Authoritative source is unavailable | the authoritative source is unavailable |
audit.unavailable | 503 | Required audit is unavailable | required audit is unavailable |
service.not_ready | 503 | Service is not ready | the service is not ready |
internal.timeout | 504 | Request timed out | request exceeded the configured timeout |
Reading the set
Section titled “Reading the set”The consultation.* codes cover record reads, lookups, and searches. The aggregate-data.* codes
cover the SDMX data and structure routes. The pairs are deliberate: a consultation and an aggregate
data request that fail the same way still carry different codes, so a caller can tell which surface
refused without inspecting the path.
Four distinctions are worth knowing before writing client code.
resource.not_foundmeans the path does not name anything this caller may reach.consultation.unresolvedmeans the operation exists and ran, and no record answered it. A caller that is authenticated but not entitled to a resource gets the sameresource.not_foundas a caller asking for a resource that was never declared, so the code cannot be used to probe what exists. The exception is deliberate: an anonymous caller asking for something whose class has any protected operation getsauth.missing_credentialfirst, so a legitimate client is told to authenticate rather than told the path is wrong.auth.invalid_credentialcollapses every token validation failure into one answer: expiry, signature, issuer, audience, unknown key, and disallowed algorithm are indistinguishable to the caller.filter.unknown_fieldfires when a filter is not declared for the operation being called, not when a column is absent from the source. The compiled contract decides what a caller may filter on, so an undeclared filter and a nonexistent column look the same.- The three
413codes separate an oversized request from an oversized answer.internal.payload_too_largeis about the request body,consultation.response_too_largeis about the record answer, andaggregate-data.too_largeis about the observation count an SDMX request would return.
Startup failures are not problems
Section titled “Startup failures are not problems”Relay compiles and verifies its sealed package before it serves anything. A failure at that stage
is not an HTTP problem: the process writes a bounded operational record on standard error and
exits, or /ready answers service.not_ready while a dependency is not yet usable. There is no
startup-only code namespace in the problem set, because a Relay that cannot activate its package
does not begin serving. See Operate Relay for what those startup records look
like.
Evidence Gateway
Section titled “Evidence Gateway”Evidence Gateway has its own closed problem set, documented at
Evidence Gateway problem types. That page is the single place the set is written
down, because the set is frozen in products/evidence/contracts/problem-contract.yaml and CI
byte-diffs the generated schema against it; a second copy of the table here would drift without a
gate to catch it.
Evidence Gateway type URIs use
https://id.registrystack.org/problems/registry-evidence/<code-path>, where
the dotted code is written with slashes in the URI path.
Every problem body has exactly type, title, status, detail, code, and
traceId members. Its static, value-free detail and public trace identifier
never disclose subject data, source diagnostics, or the server-minted audit
identifier.
Registry Mint
Section titled “Registry Mint”Registry Mint is an OAuth 2.0 token endpoint, so it does not use RFC 9457 at all. Every error
response body is the OAuth form {"error": "<code>"} over four codes (invalid_request,
unsupported_grant_type, invalid_client, and server_error), transcribed with their statuses
and causes in the Registry Mint reference. The one to know before reading it:
every client authentication failure collapses to invalid_client, so the endpoint cannot be used
to probe which client ids are registered.
Source
Section titled “Source”The Relay codes above are transcribed from ProblemCode in
crates/registry-relay-v2/src/problem.rs, which owns the code strings, titles, details, statuses,
type URIs, and response headers in one place. The trace behavior is TraceContext in the same file.
The codes this page points at rather than repeating are transcribed on their own pages from
crates/registry-evidence/src/problem.rs with products/evidence/contracts/problem-contract.yaml
(Evidence Gateway) and crates/registry-mint/src/error.rs (Registry Mint).