#[non_exhaustive]pub enum ErrorCode {
Show 38 variants
CouldNotResolveAddr,
InvalidApiCall,
SocketError,
ConnectTimeout,
InvalidUtf8,
InvalidName,
InvalidTimestamp,
AuthError,
TlsError,
HttpNotSupported,
ServerFlushError,
ConfigError,
ArrayError,
ProtocolVersionError,
InvalidDecimal,
ServerRejection,
ArrowUnsupportedColumnKind,
ArrowIngest,
FailoverRetry,
RoleMismatch,
HandshakeError,
UnsupportedServer,
ProtocolError,
InvalidBind,
ServerSchemaMismatch,
ServerParseError,
ServerInternalError,
ServerSecurityError,
LimitExceeded,
ServerLimitExceeded,
Cancelled,
FailoverWouldDuplicate,
SchemaDrift,
NoSchema,
ArrowExport,
BatchTooLarge,
StoreResendRequired,
SymbolDictFull,
}Expand description
Category of error.
This is the single, unified error category for the whole client: it spans
both ingestion (writing into QuestDB) and queries (reading out). Not every
variant can arise from every operation — the ingest path never emits the
reader-only wire/cursor categories, and a query never emits the
sender-only encode categories — but a caller handling errors from a
QuestDb pool, which spans both directions, sees one category enum.
Accessible via Error’s code method.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
CouldNotResolveAddr
The host, port, or interface was incorrect.
InvalidApiCall
Called methods in the wrong order. E.g. symbol after column.
SocketError
A network error connecting or flushing data out. Transient — obtain a fresh connection (or let the pool rotate) and retry.
The terminal, resend-required failure of the QWP/WebSocket
store-and-forward persisted symbol dictionary is a distinct code,
StoreResendRequired, so a caller can tell it
apart from a retryable socket drop by code, without matching on the
error message text.
ConnectTimeout
The TCP connect (dial) to the server exceeded the configured
connect_timeout. Distinct from SocketError
so a caller can tell a timed-out dial apart from a refused / reset
connection. Currently produced only by the QWP/WebSocket transport.
InvalidUtf8
The string or symbol field is not encoded in valid UTF-8.
This error is reserved for the C and C++ API.
InvalidName
The table name or column name contains bad characters.
InvalidTimestamp
The supplied timestamp is invalid.
AuthError
Error during the authentication process.
TlsError
Error during TLS handshake.
HttpNotSupported
The server does not support ILP-over-HTTP.
ServerFlushError
Error sent back from the server during flush.
ConfigError
Bad configuration.
ArrayError
There was an error serializing an array.
ProtocolVersionError
Validate protocol version error.
InvalidDecimal
The supplied decimal is invalid.
ServerRejection
QWP/WebSocket server rejection or terminal protocol violation.
ArrowUnsupportedColumnKind
PooledSenderCore::flush_arrow_batch_* was passed a column whose Arrow /
QuestDB kind cannot be persisted to a QuestDB table (e.g.
ARRAY(LONG, N-D) is query-result-only on the egress side and has
no QWP wire tag for ingress). Only emitted on the arrow feature.
ArrowIngest
PooledSenderCore::flush_arrow_batch_* was passed a RecordBatch that
failed client-side structural validation (column count vs schema,
name encoding, ARROW C Data Interface invariants on a freshly
imported array, etc.). Only emitted on the arrow feature.
FailoverRetry
A reconnectable failure on the column-major sender’s flush/sync path (transport error, EOF, or a closed connection). The operation has not committed; the caller should obtain a fresh connection from the pool (which rotates to a live endpoint) and re-drive from its source. Distinct from terminal failures (auth / protocol / schema / server rejection), which must not be retried.
RoleMismatch
Every reachable endpoint completed its handshake but none advertised
a role matching the configured target= filter (e.g. target=primary
against an all-replica address list, or a 421 + X-QuestDB-Role: REPLICA upgrade reject). Distinct from SocketError (“all endpoints
unreachable”) so callers can tell “no primary elected yet” from
“everything is down”.
HandshakeError
HTTP-upgrade or WebSocket handshake failure.
UnsupportedServer
Server returned an unsupported QWP version, encoding, or capability.
ProtocolError
Wire-format violation: bad magic, truncated frame, unknown discriminant, invalid varint, symbol-dict reference miss, etc.
InvalidBind
Bind parameter index, count, or value rejected client-side (before the QUERY_REQUEST hits the wire). On the query path this covers timestamp / decimal / geohash range failures alongside everything else caught at bind time.
ServerSchemaMismatch
Server-reported QWP SCHEMA_MISMATCH (status 0x03).
ServerParseError
Server-reported QWP PARSE_ERROR (status 0x05).
ServerInternalError
Server-reported QWP INTERNAL_ERROR (status 0x06).
ServerSecurityError
Server-reported QWP SECURITY_ERROR (status 0x08).
LimitExceeded
Client-side limit hit (e.g. an array row exceeds the configured per-row element cap).
ServerLimitExceeded
Server-reported QWP LIMIT_EXCEEDED (status 0x0B).
Cancelled
Query was cancelled (locally or via server CANCELLED status 0x0A).
FailoverWouldDuplicate
Mid-query failover was eligible but at least one batch had already
been delivered to the caller, and the cursor’s on_failover_reset
callback was not installed. Failover would replay the query from the
start on the new endpoint, re-delivering already-consumed rows, so the
cursor terminates with this error instead of silently duplicating.
The caller must install on_failover_reset (and discard partial state
on each invocation) or re-run the query from scratch.
SchemaDrift
Streaming Arrow adapter saw a mid-stream schema change: a later
RESULT_BATCH decoded into an Arrow schema that differs from the
snapshot captured at adapter construction. The adapter is poisoned;
the underlying cursor remains usable and the caller may re-wrap it
with a fresh as_arrow_reader() call. Only emitted on the arrow
feature.
NoSchema
Cursor::as_arrow_reader() was called on a stream that terminated
before any RESULT_BATCH was decoded — there is no schema to
snapshot. Recoverable: treat as a “no rows” result, or re-execute.
Only emitted on the arrow feature.
ArrowExport
Arrow C Data Interface export failed (e.g. arrow-rs rejected an
internal invariant on the produced ArrayData). Indicates a crate
bug; not user-recoverable. Only emitted on the arrow feature.
BatchTooLarge
An irreducible QWP/WebSocket unit (the table schema plus a single
row block) exceeds the negotiated per-batch cap
(min(max_buf_size, server X-QWP-Max-Batch-Size)). Chunk publication
splits oversize inputs into smaller frames automatically, so this only
surfaces when splitting cannot make a frame fit. Distinct from
InvalidApiCall so callers can recognise it
without matching on the error message text.
StoreResendRequired
The QWP/WebSocket store-and-forward persisted symbol dictionary is
unrecoverable, so the queued frames that reference it cannot be replayed:
a host/power crash tore the .symbol-dict side-file relative to the
queued frames, or it could not be written ahead of them. Retrying the
connection will not help — the affected rows must be re-ingested from
their source.
Terminal, and distinct from SocketError (a
transient, retryable socket drop) so a caller can tell “resend from
source” apart from “reconnect and retry” by code, without matching on
the error message text. The sender’s own reconnect/failover loops treat it
as terminal (they stop) rather than retrying it to their deadline.
SymbolDictFull
The QWP/WebSocket connection-scoped symbol dictionary is full: interning another distinct symbol would push it past its entry-count cap (2,000,000, matching the server’s ingress ceiling) or its cumulative UTF-8 heap cap (256 MiB). The dictionary accumulates every distinct symbol referenced across every column, chunk, and row-buffer flush on one connection, and is only reset by discarding that connection.
The failing frame is rejected before any byte reaches the wire and the buffer is rolled back, so that flush loses nothing and already-interned symbols keep flushing — but retrying a new symbol on the same sender can never succeed. A full dictionary therefore retires the connection on return: a pooled sender is dropped rather than recycled (so the next borrow gets a fresh, empty-dictionary connection, not the same full one), and the frames flushed earlier on it are drained / committed best-effort on the way out. So the simplest recovery is to return or drop the sender as usual and continue on a fresh borrow. If those earlier frames must not be lost, drain or commit them and check first, as below.
- Pooled row sender (
QuestDb::borrow_sender): a full dictionary marks the connection for retirement, so a plain drop (which is the pool return) drains the queue best-effort withinclose_flush_timeoutand drops the connection instead of recycling it — the next borrow gets a fresh one. (Nothing extra to call: an explicitdrop_on_return()does the same and is redundant here.)wait()first if the queued frames must not be lost. Withsf_dirconfigured they persist in the slot, but so does the dictionary, and the next borrower re-seeds from that slot’s side-file at the same size unless the slot drained first — sowait()there too, so the slot drains and the next borrower starts clean. - Pooled direct column sender
(
QuestDb::borrow_direct_column_sender): a full dictionary marks the connection spent — retired on return, but its transport is healthy and still drainable — so a plain drop commits the deferred tail best-effort and retires the connection. Itsflushis deferred (nothing is committed untilcommitorflush_and_wait), so for a checked guarantee callcommit(..)(orflush_and_wait(..)on the final chunk) and confirm it succeeded before the drop —commitstill goes through on a spent connection. Do not reach fordrop_on_return()on a full dictionary: it hard-latches the connection, which makes the drop skip the best-effort commit and discard the tail.reborrow_from_pool()likewise discards the in-flight tail (its failover contract), socommit/wait()before it if that tail matters. - Standalone (
Sender): callclose_drainand check it succeeded, then drop and reconnect. Unlike the pooled guards above, a plain drop drains nothing here —SyncProtocolHandler’sDropshuts down the ILP-over-TCP socket and has no QWP/WebSocket arm at all, so every published-but-unacked frame is discarded with no wait. This is the most lossy of the three flavours on a bare drop, not the least.close_drainis bounded byclose_flush_timeout. - C ABI: a plain
questdb_db_return_sender/questdb_db_return_direct_sendernow retires (does not recycle) a full-dictionary connection and drains / commits its pending frames best-effort — callqwp_sender_wait/qwp_direct_sender_commitfirst for a checked guarantee.questdb_db_drop_direct_senderforce-drops and skips the direct sender’s tail commit, so on a full dictionary prefer the plain return unless you mean to discard the tail.
One exception to “that flush loses nothing”, and it matters for
resends. A chunk too large for a
single frame is split, and each half is published on its own;
store-and-forward is at-least-once, so an earlier half can already be
durably queued when a later half hits the cap. Nothing is lost then
either, but the operation is no longer known-not-delivered: it is
reported as delivery-unknown, so check in_doubt
before resending — a blind resend of the whole chunk duplicates the
rows the committed prefix already carried.
Distinct from InvalidApiCall — a caller
mistake with no recovery — so callers can recognise a full dictionary
by code and take that specific action, without matching on the error
message text.
Trait Implementations§
impl Copy for ErrorCode
impl Eq for ErrorCode
impl StructuralPartialEq for ErrorCode
Auto Trait Implementations§
impl Freeze for ErrorCode
impl RefUnwindSafe for ErrorCode
impl Send for ErrorCode
impl Sync for ErrorCode
impl Unpin for ErrorCode
impl UnsafeUnpin for ErrorCode
impl UnwindSafe for ErrorCode
Blanket Implementations§
impl<T> Allocation for T
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more