nquic_error (nquic v1.0.0)
View SourceCanonical error taxonomy for nquic.
Every error that crosses the public surface of nquic or nquic_lib
is shaped by this module so callers can pattern-match exhaustively on
nquic:error_reason()/0.
Two responsibilities:
- Constructors:
closed/0,timeout/1,transport/1,tls/1,application/2,protocol/1,flow_control/1,opts/1,connect/1,listen/1return canonical{error, error_reason()}tuples. Use them at sites that already know which bucket the term belongs to. - Mappers:
from_socket/2,from_tls_alert/1,from_handshake/1,from_connection_close/1,wrap/1,wrap_result/1translate raw upstream shapes (POSIX atoms, TLS alerts,#connection_close{}records, internal atoms) into the canonical sum.
wrap/1 is the single funnel for unknown error terms at the public
boundary; already-canonical values pass through unchanged.
Error-handling convention contract
nquic:error_reason/0 is a closed, {error, _}-wrapped,
category-classified tagged union. The supported way to interrogate
a value is the trio:
category/1: one atom from the small closed setclosed | timeout | transport | tls | application | protocol | flow_control | opts | connect | listen(never crashes on a canonical value).is_retryable/1:boolean().format/1: human-readableiodata().
Callers should classify and branch via these functions, not by pattern-matching the inner shape (which may gain arms within a category without a major version bump; the category set will not).
This is the same convention nhttp_error follows
({error, {category(), reason()}} plus its own
category/1 / is_retryable/1 / format/1). The two taxonomies are
therefore structurally parallel by convention, not coupled: nquic
ships no adapter and depends on no HTTP library. A consumer that
needs to project nquic failures into its own error vocabulary writes
a small total adapter over category/1 at its own boundary. nquic
deliberately does not know nhttp exists, so it stays reusable by any
non-HTTP QUIC consumer and independently releasable.
Summary
Types
Wide internal error type carried by modules that have not yet been
funnelled through a constructor. Callers at the public boundary must
pass these through wrap/1 before returning to the user.
Application-domain close reason carrying peer error code and phrase.
Category tag returned by category/1, useful for telemetry.
Closed error taxonomy returned by every public function. The outer arm classifies the failure; the inner value carries detail without growing the union.
Flow control or congestion-control blocking outcomes.
Options / configuration / API-misuse errors.
Protocol-level errors: wire format, parser, RFC 9000 violations.
Phase tag for {timeout, Phase} outcomes.
TLS-layer error reasons (peer alerts or local handshake validation).
Transport-domain error reasons (peer CONNECTION_CLOSE 0x1c or local I/O).
Functions
Application-domain CONNECTION_CLOSE from the peer.
Category tag for telemetry / log fields.
Terminal connection state.
Client-side DNS / socket open / connect failure (POSIX atom).
Local flow control / congestion blocking.
Human-readable rendering for log lines.
Map a peer-sent #connection_close{} record to a canonical
{transport, _} or {application, Code, Reason} error.
Map a TLS-handshake-side internal failure (no-PSK, binder mismatch,
malformed finished, ...) to a canonical {tls, _} error.
Map a raw POSIX atom from a socket / inet call to the matching
canonical bucket according to which operation produced it.
Origin is one of connect, listen, transport.
Map a TLS alert atom or {tls_alert, _} record to a canonical
{tls, _} error.
Whether the caller may sensibly retry after this error.
Server-side socket bind / listen failure (POSIX atom).
Options / configuration / API-misuse error.
Wire-format / protocol violation detected locally.
Timeout in a named phase.
TLS-layer error: peer alert or local handshake validation.
Transport-layer error: peer CONNECTION_CLOSE (0x1c) or local I/O.
Normalise any term into the canonical taxonomy. Already-canonical values pass through unchanged.
Generic dispatcher used by wrap/1. Exported for the rare site that
already destructured the {error, _} tuple and only has the payload.
Wrap an {ok, _} | {error, _} result so the error arm is canonical.
The ok and {ok, _} arms pass through unchanged.
Types
Wide internal error type carried by modules that have not yet been
funnelled through a constructor. Callers at the public boundary must
pass these through wrap/1 before returning to the user.
-type application_reason() :: {non_neg_integer(), binary()}.
Application-domain close reason carrying peer error code and phrase.
-type category() ::
closed | timeout | transport | tls | application | protocol | flow_control | opts | connect |
listen.
Category tag returned by category/1, useful for telemetry.
-type error_reason() :: closed | fin | {timeout, timeout_phase()} | {transport, transport_reason()} | {tls, tls_reason()} | {application, non_neg_integer(), binary()} | {protocol, protocol_reason()} | {flow_control, flow_control_reason()} | {opts, opts_reason()} | {connect, inet:posix() | atom()} | {listen, inet:posix() | atom()}.
Closed error taxonomy returned by every public function. The outer arm classifies the failure; the inner value carries detail without growing the union.
-type flow_control_reason() ::
flow_control_error | stream_limit_error | congestion_control_blocked | eagain | partial_send |
stream_blocked.
Flow control or congestion-control blocking outcomes.
-type opts_reason() :: not_owner | not_found | not_connected | not_established | not_writable | unknown_request | unknown_stream | invalid_stream | invalid_stream_id | stream_not_found | stream_closed | stream_reset | empty | no_data | sups_not_ready | draining | ctx_requires_wait | not_supported_in_mode | {missing_option, atom()} | {misplaced_option, atom()} | {certfile, atom()} | {unsupported_cipher_suite, binary() | atom()} | {already_started, pid()}.
Options / configuration / API-misuse errors.
-type protocol_reason() :: protocol_violation | frame_encoding_error | packet_too_short | integrity_check_failed | final_size_error | migration_disabled | duplicate_parameter | truncated_param_value | transport_parameter_error | no_available_cids | retry_token_too_short | invalid_retry_token | datagrams_not_negotiated | datagram_too_large | invalid_packet | incomplete_binary | key_update_pending | no_initial_keys | no_zero_rtt_keys | no_probe_needed | overflow | stream_state_error | decrypt_failed | {transport_parameter_error, atom()} | {processing_failed, dynamic()} | {encoding_failed, dynamic()} | {flight_generation_failed, dynamic()} | {decrypt_failed, dynamic()}.
Protocol-level errors: wire format, parser, RFC 9000 violations.
-type timeout_phase() :: handshake | idle | recv | send | accept.
Phase tag for {timeout, Phase} outcomes.
-type tls_reason() :: unexpected_message | handshake_failure | bad_certificate | unsupported_certificate | certificate_revoked | certificate_expired | certificate_unknown | illegal_parameter | unknown_ca | access_denied | decode_error | decrypt_error | protocol_version | insufficient_security | internal_error | inappropriate_fallback | user_canceled | missing_extension | unsupported_extension | unrecognized_name | bad_certificate_status_response | unknown_psk_identity | certificate_required | no_application_protocol | no_psk | no_matching_psk | no_static_key | no_peercert | binder_mismatch | binder_verification_failed | psk_identity_binder_mismatch | client_finished_verification_failed | malformed_finished | malformed_new_session_ticket | not_new_session_ticket | invalid_ticket_cipher | invalid_ticket_format | ticket_decrypt_failed | ticket_too_short | {bad_cert, dynamic()} | {hostname_mismatch, binary()} | {alert, atom()}.
TLS-layer error reasons (peer alerts or local handshake validation).
-type transport_reason() :: no_error | internal_error | connection_refused | flow_control_error | stream_limit_error | stream_state_error | final_size_error | frame_encoding_error | transport_parameter_error | connection_id_limit_error | protocol_violation | invalid_token | application_error | crypto_buffer_exceeded | key_update_error | aead_limit_reached | no_viable_path | crypto_error | idle_timeout | stateless_reset | version_negotiation | closed_by_peer | {posix, inet:posix()} | {peer_close, non_neg_integer(), binary()}.
Transport-domain error reasons (peer CONNECTION_CLOSE 0x1c or local I/O).
Functions
-spec application(non_neg_integer(), binary()) -> {error, error_reason()}.
Application-domain CONNECTION_CLOSE from the peer.
-spec category(error_reason()) -> category().
Category tag for telemetry / log fields.
-spec closed() -> {error, error_reason()}.
Terminal connection state.
-spec connect(inet:posix() | atom()) -> {error, error_reason()}.
Client-side DNS / socket open / connect failure (POSIX atom).
-spec flow_control(flow_control_reason()) -> {error, error_reason()}.
Local flow control / congestion blocking.
-spec format(error_reason()) -> iolist().
Human-readable rendering for log lines.
-spec from_connection_close(#connection_close{error_code :: non_neg_integer(), frame_type :: non_neg_integer(), reason_phrase :: binary(), is_application :: boolean()}) -> {error, error_reason()}.
Map a peer-sent #connection_close{} record to a canonical
{transport, _} or {application, Code, Reason} error.
-spec from_handshake(atom() | tuple()) -> {error, error_reason()}.
Map a TLS-handshake-side internal failure (no-PSK, binder mismatch,
malformed finished, ...) to a canonical {tls, _} error.
-spec from_socket(connect | listen | transport, inet:posix() | atom()) -> {error, error_reason()}.
Map a raw POSIX atom from a socket / inet call to the matching
canonical bucket according to which operation produced it.
Origin is one of connect, listen, transport.
-spec from_tls_alert(atom() | tuple()) -> {error, error_reason()}.
Map a TLS alert atom or {tls_alert, _} record to a canonical
{tls, _} error.
-spec is_retryable(error_reason()) -> boolean().
Whether the caller may sensibly retry after this error.
-spec listen(inet:posix() | atom()) -> {error, error_reason()}.
Server-side socket bind / listen failure (POSIX atom).
-spec opts(opts_reason()) -> {error, error_reason()}.
Options / configuration / API-misuse error.
-spec protocol(protocol_reason()) -> {error, error_reason()}.
Wire-format / protocol violation detected locally.
-spec timeout(timeout_phase()) -> {error, error_reason()}.
Timeout in a named phase.
-spec tls(tls_reason()) -> {error, error_reason()}.
TLS-layer error: peer alert or local handshake validation.
-spec transport(transport_reason()) -> {error, error_reason()}.
Transport-layer error: peer CONNECTION_CLOSE (0x1c) or local I/O.
-spec wrap(term()) -> {error, error_reason()}.
Normalise any term into the canonical taxonomy. Already-canonical values pass through unchanged.
-spec wrap_reason(term()) -> {error, error_reason()}.
Generic dispatcher used by wrap/1. Exported for the rare site that
already destructured the {error, _} tuple and only has the payload.
-spec wrap_result(ok | {ok, T} | {error, term()}) -> ok | {ok, T} | {error, error_reason()}.
Wrap an {ok, _} | {error, _} result so the error arm is canonical.
The ok and {ok, _} arms pass through unchanged.