#[non_exhaustive]pub enum Error {
Show 28 variants
Protocol(ProtocolError),
Io(Error),
Runtime(String),
RedirectUnsupported,
InvalidRedirectData(String),
ConnectRedirectLoop(u8),
ListenerRefused(String),
AllAddressesFailed(String),
UnsupportedSni(String),
UnexpectedPacket(u8),
ConnectResendLoop(u8),
FastAuthRequired,
MissingSessionField(&'static str),
CallTimeout(u32),
NoRows,
TooManyRows,
Cancelled,
ConnectionClosed(String),
Tls(String),
Wallet(WalletError),
AccessTokenRequiresTcps,
IamTokenProofOfPossession,
TokenSource(TokenSourceError),
UnsupportedAuthMode(UnsupportedAuthMode),
SessionlessTransaction(SessionlessError),
UnknownTransactionState(u32),
Bind(BindError),
Conversion(ConversionError),
}Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Protocol(ProtocolError)
Io(Error)
Runtime(String)
RedirectUnsupported
The listener redirected the connection to a target whose shape this
driver refuses to follow: the redirect address demands a transport
protocol CHANGE. Continuing a tcps connect over plain tcp would be
a silent TLS downgrade, and a mid-connect tcp -> tcps upgrade is
not supported; a redirect that keeps the original transport protocol
is followed transparently.
InvalidRedirectData(String)
The listener answered CONNECT with a REDIRECT packet whose redirect data could not be understood (truncated length prefix, missing the NUL separator between the target address and its connect data, or an unparseable target address). The payload describes the defect; the raw redirect bytes are not echoed verbatim.
ConnectRedirectLoop(u8)
The listener kept answering every CONNECT with another REDIRECT. A real redirect chain is one hop (shared server / RAC); the bound only guards against a redirect loop between misconfigured listeners.
ListenerRefused(String)
AllAddressesFailed(String)
Every address in a multi-address connect descriptor (ADDRESS_LIST or
several ADDRESS entries) failed to establish a transport. The payload
aggregates the per-address failure reasons in the order they were tried.
The connection never reached a listener, so there is nothing to reuse.
UnsupportedSni(String)
use_sni=true was explicitly requested but the Oracle TCPS SNI string
(S{len}.{service}.V3.{version}) is not a valid rustls DNS name (its
trailing all-numeric label is rejected by RFC-strict rustls), so it
cannot be transmitted. The driver fails closed here instead of silently
connecting without SNI. Reconnect with use_sni=false (the default) to
rely on the post-handshake Oracle DN match, which secures the connection
without SNI.
UnexpectedPacket(u8)
ConnectResendLoop(u8)
FastAuthRequired
MissingSessionField(&'static str)
CallTimeout(u32)
NoRows
TooManyRows
Cancelled
The in-flight operation was explicitly cancelled by the user (via
Connection::cancel or by dropping a cancellable fetch future), the
driver’s analog of the server-side ORA-01013 “user requested cancel of
current operation”. Like a Self::CallTimeout (DPY-4024), a cancel
drains the wire and leaves the session ALIVE and the connection clean and
reusable: it is therefore not Self::is_connection_lost and is
Self::is_transient (re-run the idempotent call on the same
connection). It is distinguished from CallTimeout only so callers can
tell a deliberate cancel apart from a deadline overrun.
ConnectionClosed(String)
The connection was closed because recovery from a prior failure could
not complete: most commonly a second timeout while draining the
server’s response after a Self::CallTimeout break (mirroring the
reference ERR_CONNECTION_CLOSED raised when the post-break
_receive_packet itself times out, protocol.pyx:454-458). Unlike
Self::CallTimeout, the wire stream could not be left clean, so the
connection is dead and must be discarded — Self::is_connection_lost
is true for this variant. The payload is the human-readable reason.
Tls(String)
A TCPS/TLS transport error (wallet load, handshake, or server-cert / DN-match failure).
Wallet(WalletError)
A wallet-location or wallet-format error. Kept distinct from generic TLS failures so callers can classify unsupported wallet formats and operator setup issues without parsing strings.
AccessTokenRequiresTcps
Access-token authentication was requested over a non-TLS transport.
A database access token must only travel over TCPS so it is not exposed
in clear text (reference protocol.pyx ERR_ACCESS_TOKEN_REQUIRES_TCPS /
DPY-3001). Reconnect with a tcps:// connect string. The token itself is
never included in this error.
IamTokenProofOfPossession
The OCI IAM database-token proof-of-possession private key could not be used to sign the auth header: it was not a readable PKCS#8 RSA key, or the RSA-PKCS1v15-SHA256 signing operation failed. The key material, the token, and the signed header are never included in this error — only a fixed diagnostic is surfaced.
TokenSource(TokenSourceError)
A pluggable TokenSource failed to produce a database access token.
The failure is a redacted TokenSourceError class; the token and any
provider detail never appear in this error.
UnsupportedAuthMode(UnsupportedAuthMode)
The caller selected a known authentication mode that this thin build does not implement. The mode is structured so diagnostic tools can distinguish capability gaps from bad credentials, listener failures, or TLS setup errors without parsing the display string.
SessionlessTransaction(SessionlessError)
A sessionless transaction client-API misuse (reference ERR_SESSIONLESS_* / DPY-3034/3035/3036). The payload is the DPY full code so the shim can raise the matching DatabaseError.
UnknownTransactionState(u32)
A TPC (two-phase commit) state machine returned an unexpected out state
(reference ERR_UNKNOWN_TRANSACTION_STATE / DPY-5010). The payload is
the unexpected state value.
Bind(BindError)
A client-side bind payload was provably incompatible with the SQL text.
Conversion(ConversionError)
A typed FromSql conversion failed: the fetched value did not match
the requested Rust type, was out of range, or could not be parsed. The
payload describes the mismatch.
Implementations§
Source§impl Error
Structured classification of an Error.
impl Error
Structured classification of an Error.
These accessors promote the driver’s internal retry knowledge (which ORA
codes mean “the session died”, “the resource was busy”, “the cached plan is
stale”) into a public, matchable taxonomy. python-oracledb gives you a bare
.code integer and leaves the classification to you; here the curated lists
ship with the driver so production retry / circuit-breaker code is trivial:
if err.is_connection_lost() {
// reconnect, then retry
} else if err.is_retryable() {
// back off and retry on the same connection
}The classification sources, in priority order:
- The structured server error code (
ServerErrorInfo.code) when present. - Otherwise the
ORA-NNNNNprefix parsed from the error message.
The curated transient and connection-lost code sets are maintained in this module and exposed through the stable methods below.
Sourcepub fn resource_limit(&self) -> Option<ResourceLimit>
pub fn resource_limit(&self) -> Option<ResourceLimit>
Structured resource-limit details when this error came from
oracledb_protocol::wire::ProtocolLimits.
Sourcepub fn ora_code(&self) -> Option<i32>
pub fn ora_code(&self) -> Option<i32>
The Oracle error number (ORA-NNNNN) this error carries, if any.
Returns the structured ServerErrorInfo.code when the error came back
on the structured path; otherwise it parses the ORA- prefix out of the
server message. None for non-server errors (I/O, timeouts, protocol
decode failures) and server messages with no ORA- code.
The value is an i32 (rather than u32) so it composes directly with
the i32-typed codes most retry tables and logging layers already use;
every real Oracle code fits comfortably.
Sourcepub fn oracle_code(&self) -> Option<i32>
pub fn oracle_code(&self) -> Option<i32>
Alias for Self::ora_code using the API-design terminology.
Sourcepub fn offset(&self) -> Option<i32>
pub fn offset(&self) -> Option<i32>
The server-reported parse offset / error position for this error, if the
server provided one (1-based character offset into the SQL text for a
parse error). Only the structured server-error path retains the offset;
None everywhere else, and None when the server reported offset 0.
Sourcepub fn caret(&self, sql: &str) -> Option<String>
pub fn caret(&self, sql: &str) -> Option<String>
Render a compiler-style caret diagnostic for a parse error, pointing at
the exact character in sql the server flagged (Error::offset):
ORA-00942: table or view does not exist
|
1 | select * from no_such_table
| ^Returns None when the error carries no parse offset (only structured
server parse errors do). The headline is this error’s first Display
line (the ORA- code + message). python-oracledb hands you a bare offset
integer and leaves the rendering to you; this does it.
Sourcepub fn connection_disposition(&self) -> ConnectionDisposition
pub fn connection_disposition(&self) -> ConnectionDisposition
Whether the connection that surfaced this error is still reusable. A dead disposition means the session was killed, the socket was reset, or the server reported one of the session-dead Oracle codes; callers should discard the connection before continuing.
Raw I/O errors (Error::Io) and the recovery-failure
Error::ConnectionClosed also count as connection-lost: the transport
is no longer usable.
A plain Error::CallTimeout is deliberately not connection-lost.
On a call timeout the driver sends a BREAK, then drains the server’s
in-flight response and the RESET handshake, leaving the wire stream
clean and the connection reusable — exactly as python-oracledb does for
DPY-4024 (ERR_CALL_TIMEOUT_EXCEEDED), which, unlike DPY-4011
(ERR_CONNECTION_CLOSED), does not set is_session_dead
(errors.py:124-125). The connection survives; retry on the same one. Only
when that drain itself fails (a second timeout) does the driver give up
and surface Error::ConnectionClosed, which is connection-lost.
pub fn is_connection_lost(&self) -> bool
Sourcepub fn is_transient(&self) -> bool
pub fn is_transient(&self) -> bool
Whether this error is transient: the operation failed for a reason
expected to clear on its own (lock contention, deadlock victim, listener
hand-off congestion, resource-manager throttle, or a call timeout), so
the same call may be retried on the same connection after a short
back-off. Does not include connection-lost codes (those need a
reconnect first — use Self::is_connection_lost).
Error::CallTimeout is transient: after the driver drains the wire the
connection is clean and reusable, so re-running the (idempotent) call on
the same connection — e.g. with a longer timeout — is the natural retry.
Error::Cancelled is transient for the same reason: an explicit cancel
also drains the wire and leaves the session alive.
Sourcepub fn retry_hint(&self) -> RetryHint
pub fn retry_hint(&self) -> RetryHint
Conservative retry guidance. Any returned retry action still requires the caller to know the operation is idempotent; non-idempotent operations must not be replayed automatically.
pub fn is_retryable(&self) -> bool
Trait Implementations§
Source§impl Error for Error
impl Error for Error
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()