http_gun/error
Describes why an HTTP request, a body read or a scripted exchange failed.
A Failure is opaque. Branch on its closed Kind with kind, and ask
is_retryable whether sending the request again is safe:
case http_gun.send(client, req) {
Ok(buffered) -> handle(buffered.response)
Error(failure) ->
case error.is_retryable(failure, idempotent: False) {
True -> retry_later()
False -> give_up(error.describe(failure))
}
}
Every failure carries submission Evidence: NotSent when the request
never reached the network, MaybeSent when the server may have received
it. Neither proves the server acted. status returns the response status
when final headers had arrived before the failure, for example when a body
exceeded its limit, and headers returns that response’s headers, so a
caller can still read retry-after from a 429 whose body was too large.
Reason gives detail and may gain variants in a minor release; match it
with a _ arm, and branch on Kind instead where you can. name is a
stable identifier for logs and stored records, and to_json with
decoder round-trips a failure. A failure never holds a URL, header,
query or body from the request; the response headers it may hold have
the client’s redaction applied (config.with_redaction).
Types
Whether the request may have reached the server. A failure never reports a completed exchange: a completed exchange is a response.
pub type Evidence {
NotSent
MaybeSent
}
Constructors
-
NotSentThe request was refused or failed before any byte reached the network. Sending it again cannot duplicate an effect.
-
MaybeSentThe request may have reached the server, which may have acted on it.
A failed operation: its reason, submission evidence and, when final headers had arrived, the response status and headers.
pub opaque type Failure
The closed classification of a failure. It never gains variants, so an exhaustive match on it keeps compiling across minor releases.
pub type Kind {
InvalidInput
Refused
Unavailable
Network
TimedOut
TooLarge
CancelledLocally
Misuse
Playback
}
Constructors
-
InvalidInputThe request or a per-call setting is malformed. Fix the caller.
-
RefusedThe destination policy refused the host or a resolved address, or the client requires a view destination and the view set none.
-
UnavailableThe client is stopped, restarting or full, it timed out waiting for a connection from its pool, or its recording closed.
-
NetworkName resolution, connecting, TLS or the exchange itself failed.
-
TimedOutA connect, request or idle timeout expired.
-
TooLargeA size limit was exceeded.
-
CancelledLocallyThe caller cancelled the request or closed its body.
-
MisuseThe body was read concurrently or from a process that does not own it.
-
PlaybackA scripted or cassette client found no matching exchange.
The category and unit of a size limit. May gain variants in a minor release.
pub type LimitKind {
RequestBodyBytes
RequestHeaderBytes
RequestHeaderCount
ResponseHeaderBytes
ResponseHeaderCount
BufferedBytes
ResponseBodyBytes
BatchBytes
}
Constructors
-
RequestBodyBytes -
RequestHeaderBytes -
RequestHeaderCount -
ResponseHeaderBytes -
ResponseHeaderCount -
BufferedBytesResponse bytes buffered between the network and the reader (
config.with_max_buffered_bytes). -
ResponseBodyBytesBody bytes collected by
sendorbatch(config.with_max_response_body_bytes,http_gun.with_body_limit). -
BatchBytesBody bytes retained by one
batchcall (config.with_max_batch_bytes).
Why a request failed, in detail. May gain variants in a minor release:
match it with a _ arm, or branch on kind.
pub type Reason {
InvalidRequest(RequestProblem)
ClientClosed
AdmissionFull
PoolTimeout
DestinationRejected(destination.Rejection)
ViewDestinationRequired
ResolutionFailed
ConnectTimeout
ConnectionFailed(TransportCause)
RequestFailed(TransportCause)
DeadlineExceeded
IdleTimeout
ReadConflict
WrongOwner
Closed
Cancelled
LimitExceeded(kind: LimitKind, limit: Int, observed: Int)
PlaybackMismatch(position: Int)
PlaybackExhausted
RecordingClosed
}
Constructors
-
InvalidRequest(RequestProblem) -
ClientClosedThe client is stopped, or restarting under its supervisor.
-
AdmissionFullThe client’s queue of waiting requests is full.
-
PoolTimeoutNo connection became available within the pool timeout.
-
DestinationRejected(destination.Rejection) -
ViewDestinationRequiredThe client was configured with
config.require_view_destination, and the request’s view chose no destination withhttp_gun.with_destination: no policy set a host list or refused an address class the client admits. -
ResolutionFailed -
ConnectTimeoutResolving and connecting did not finish within the connect timeout.
-
ConnectionFailed(TransportCause) -
RequestFailed(TransportCause) -
DeadlineExceededThe request timeout or the per-call deadline expired.
-
IdleTimeoutNo bytes arrived within the idle timeout while a read was waiting.
-
ReadConflict -
WrongOwner -
ClosedThe body was closed, or its owner or client stopped.
-
Cancelled -
LimitExceeded(kind: LimitKind, limit: Int, observed: Int) -
PlaybackMismatch(position: Int)The request did not match the scripted exchange at this position, counted from 0. The exchange stays in place.
-
PlaybackExhaustedEvery scripted exchange has been used.
-
RecordingClosedThe recording behind a recording client is finishing or finished.
What was wrong with a request or a per-call setting. May gain variants in a minor release.
pub type RequestProblem {
BodyNotBytes
InvalidMethod
InvalidOrigin
InvalidTarget
InvalidHeader
InvalidBodyLimit
InvalidBatch
}
Constructors
-
BodyNotBytesThe body is a bit array whose size is not a whole number of bytes.
-
InvalidMethodThe method is not an HTTP token.
-
InvalidOriginThe host is empty or malformed, or the port is outside 1..65535.
-
InvalidTargetThe path or query contains whitespace or control characters, or the path does not start with
/. -
InvalidHeaderA header name is not a lowercase token, or a value contains CR, LF or NUL.
-
InvalidBodyLimitA body limit set with
http_gun.with_body_limitis negative. -
InvalidBatchA batch needs 1 to 1,024 workers and at most 10,000 requests.
A stable category of transport error. UnknownTransport keeps the
uncertainty; no dependency term or server-supplied text is exposed. May
gain variants in a minor release.
pub type TransportCause {
NameResolutionFailed
ConnectionRefused
CertificateRejected
TlsFailed
ConnectionReset
PeerClosed
PeerDraining
ProtocolError
HeaderLimitReached
TransportTimeout
UnexpectedProtocol
UnknownTransport
}
Constructors
-
NameResolutionFailed -
ConnectionRefused -
CertificateRejected -
TlsFailed -
ConnectionReset -
PeerClosed -
PeerDraining -
ProtocolError -
HeaderLimitReachedGun refused a response header or trailer list over its count limit before delivering it. Gun does not report the measured value.
-
TransportTimeout -
UnexpectedProtocol -
UnknownTransport
Values
pub fn decoder() -> decode.Decoder(Failure)
Decode the JSON that to_json writes. An unknown name fails to decode.
pub fn describe(failure: Failure) -> String
A one-line description for logs and user interfaces. It never contains a URL, header, query or body.
pub fn headers(failure: Failure) -> List(#(String, String))
The response headers, in arrival order with duplicates kept, when final
headers had arrived before a send or batch failure; otherwise [].
The client’s redaction (config.with_redaction) has removed its
listed headers, the credential headers by default. A streaming caller
already holds the headers in its Response.
// A 429 whose body exceeded `with_body_limit(_, _, Fail)`.
list.key_find(error.headers(failure), "retry-after")
pub fn is_retryable(
failure: Failure,
idempotent idempotent: Bool,
) -> Bool
Whether sending the same request again is safe and may succeed.
A NotSent failure of kind Unavailable, Network or TimedOut is
retryable. A MaybeSent failure of those kinds is retryable only for an
idempotent request, because the server may already have acted on it. No
other kind is retryable. HTTP Gun itself never retries.
pub fn name(failure: Failure) -> String
A stable identifier for logs, metrics and stored records, such as
"connection_failed.connection_refused" or
"limit_exceeded.response_body_bytes". decoder reads it back.
pub fn new(reason: Reason, evidence: Evidence) -> Failure
Build a failure, for scripted replies and test doubles.
pub fn status(failure: Failure) -> option.Option(Int)
The response status, when final headers had arrived before the failure. A body over its limit fails with the status of the response it belonged to.
pub fn to_json(failure: Failure) -> json.Json
Encode a failure as JSON, for stored records such as a durable step
error. decoder reads it back to an equal failure. Response headers, when
present, are stored as [name, value] pairs, after the client’s
redaction.
{"name": "limit_exceeded.response_body_bytes", "evidence": "maybe_sent",
"status": 429, "headers": [["retry-after", "30"]],
"limit": 8388608, "observed": 8388609}
pub fn with_headers(
failure: Failure,
headers: List(#(String, String)),
) -> Failure
Record the response headers that had arrived before the failure, replacing any recorded before. The caller applies its own redaction.