Documentation
¶
Overview ¶
Package wireerror is the error contract: the typed, wavefront-originated failures returned to a client as a proper HTTP status + standard headers + the `X-Wavefront-Error` code + a fixed `wavefront.v0.Error` protobuf body. Established in v0.1 and stable through v1.0 (iterated additively). The code/ status/header table here is authoritative against docs/protocol.md.
Index ¶
- Constants
- func IsCapabilityCeiling(status int) bool
- func Write(w http.ResponseWriter, werr *Error, contractVersion string)
- type Error
- func DecodeFailed(msg string) *Error
- func InternalError(msg string) *Error
- func RequestBodyTooLarge(msg string) *Error
- func TransformFailedRequest(msg string) *Error
- func TransformFailedResponse(msg string) *Error
- func Unavailable(msg string) *Error
- func UnknownRoute(msg string) *Error
- func UnsupportedContractVersion(msg string) *Error
- func UnsupportedMediaType(msg string) *Error
- func UpstreamError(msg string) *Error
- func UpstreamStatus(httpStatus int, msg string) *Error
- func UpstreamTimeout(msg string) *Error
Constants ¶
const ( HeaderContentType = "Content-Type" HeaderContractVersion = "X-Wavefront-Contract-Version" HeaderWavefrontError = "X-Wavefront-Error" )
Wavefront response header names that the wire-error envelope owns — kept here, alongside the codes, so the server and any other emitter cannot drift from the protocol definition.
const MediaTypeProtobuf = "application/protobuf"
MediaTypeProtobuf is the single request and response media type the v0.1 codec contract names. Every wire-error envelope has Content-Type set to this value; an inbound request that carries a body must declare it. A future multi-codec selector (issue #44) would replace direct comparison against this constant with a per-codec table.
const VersionUnknown = "unknown"
VersionUnknown is the X-Wavefront-Contract-Version value to send when negotiation has not resolved a real version yet — a pre-negotiate error, a panic before the bundle is consulted, or any other path that lacks request context. It keeps the header well-defined on every response, success or error, as docs/protocol.md requires.
Variables ¶
This section is empty.
Functions ¶
func IsCapabilityCeiling ¶ added in v0.7.0
IsCapabilityCeiling reports whether status names an HTTP feature wavefront does not model and never will at the proxy edge: 206 Partial Content (no Range support), 207/208 WebDAV, 226 IM Used (delta encoding), and every 3xx redirect. Such a status is a hard 502 regardless of any declared binding or per-route strictness — it is a capability statement, not a policy choice.
func Write ¶ added in v0.5.0
func Write(w http.ResponseWriter, werr *Error, contractVersion string)
Write emits a wavefront-originated failure as a fully-formed wire-error envelope: status, standard + extension headers, and the protobuf body. It is the single path every emitter calls — direct callers in handlers, the panic-recovery middleware, and any future emitter must go through this function so the on-wire shape cannot drift.
contractVersion is the value sent in X-Wavefront-Contract-Version; pass VersionUnknown when no negotiation has resolved a real version yet.
Types ¶
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is a typed, wavefront-originated failure. It satisfies the error interface so it can flow through normal Go error handling.
`status` is per-instance rather than per-code because `upstream_status` parameterizes the HTTP status across any undeclared non-success status outside the capability ceiling. Every other code in the table has a fixed status — passed at construction and never varied.
`retryAfter` is the verbatim header value to emit. It is empty for every code except `upstream_timeout` (which fixes it to "0"), `upstream_status` on a 429 whose upstream supplied a Retry-After header, and `unavailable` emitted by the proxy bundle-gate (which attaches a short fixed hint so clients back off briefly during boot).
func DecodeFailed ¶
DecodeFailed — the client body did not decode into the contract's request_message. 400.
func InternalError ¶ added in v0.5.0
InternalError — an unrecoverable fault inside wavefront itself: a panic in the request path, a programmer error caught at runtime, anything that is not a client / upstream condition. 500. The detail message should not leak internals to clients; callers pass a short, fixed string and rely on logs for the panic value and stack trace.
func RequestBodyTooLarge ¶
RequestBodyTooLarge — the inbound body exceeded WAVEFRONT_MAX_BODY_BYTES. 413.
func TransformFailedRequest ¶ added in v0.2.0
TransformFailedRequest — a request transform verb could not apply: the decoded request is well-formed but unprocessable under this contract's mapping. 422 (RFC 9110 §15.5.21).
func TransformFailedResponse ¶ added in v0.2.0
TransformFailedResponse — a response transform verb could not apply: the live internal shape drifted from the bundle's response stanzas. Same fault class as upstream_error. 502.
func Unavailable ¶ added in v0.5.0
Unavailable — the proxy cannot serve right now because the bundle is not loaded yet. 503. Issue #39's matrix extends this code — used on the /ready ops endpoint since v0.1 — to the proxy data path: a request that races bundle-load at boot returns this envelope rather than the misleading `upstream_error` 502 it used to (there is no upstream involved). The caller is expected to attach a short Retry-After hint with `.WithRetryAfter(...)` so well-behaved clients back off briefly and retry. Graceful drain is handled implicitly by http.Server.Shutdown (the bundle pointer is never cleared at shutdown), so accepted requests in the drain window still find a live bundle and finish normally.
func UnknownRoute ¶ added in v0.5.0
UnknownRoute — no contract in the bundle binds the inbound request's (path, method). Wrong-method folds into this code: a request whose path matches a registered route but whose method differs returns the same envelope (no 405, no `Allow` header), because each contract names exactly one method and the bundle is the only routing source of truth. 404.
func UnsupportedContractVersion ¶
UnsupportedContractVersion — the contract-version header is missing, unknown, or unsupported. 400.
func UnsupportedMediaType ¶ added in v0.5.0
UnsupportedMediaType — the inbound request declared a Content-Type that is not the contract's protobuf media type. Distinct from `decode_failed`: a wrong envelope is rejected before the body is read, so this code is reserved for the envelope mismatch and `decode_failed` is reserved for a valid envelope whose bytes don't parse. 415 (RFC 9110 §15.5.16).
func UpstreamError ¶
UpstreamError — the upstream returned a non-2xx, was unreachable, or its reply could not be encoded. 502.
func UpstreamStatus ¶ added in v0.5.0
UpstreamStatus — the upstream returned an undeclared non-success status outside the capability ceiling, on a non-strict route. The upstream's status is preserved on the response (so a 503 stays a 503); the body is a wavefront.v0.Error aid envelope whose message field relays the upstream body (UTF-8-coerced), so the wire-error body type holds while the client still sees the upstream's own detail. This is the only wire-error code whose HTTP status is parameterized — every other constructor pins a fixed status.
For an upstream 429, the caller can attach the upstream's Retry-After value with `.WithRetryAfter(...)`; the header is relayed verbatim. For any other status, Retry-After is not emitted.
func UpstreamTimeout ¶
UpstreamTimeout — the upstream exceeded WAVEFRONT_REQUEST_TIMEOUT_MS. 504.
func (*Error) HTTPStatus ¶
func (*Error) Headers ¶
Headers is the standard + extension header set for this failure. Content-Type is always the protobuf media type; Retry-After is set only where retrying is semantically meaningful. The X-Wavefront-Error / X-Wavefront-Contract-Version headers are written by the server (the latter needs request context the error itself does not carry).
func (*Error) WithRetryAfter ¶ added in v0.5.0
WithRetryAfter returns a shallow copy of e with the given Retry-After header value attached. An empty string is a no-op so callers can pass `uresp.Header.Get("Retry-After")` directly without branching on presence. Used by the upstream 429 passthrough and by the proxy bundle-gate's `unavailable` emission; other codes either set Retry-After at construction (upstream_timeout's fixed "0") or never emit it.