Skip to main content

ruststream_rdkafka/
error.rs

1//! The crate error type shared by the broker, publishers, and subscribers.
2
3use std::error::Error as StdError;
4
5use thiserror::Error;
6
7/// Errors returned by [`KafkaBroker`](crate::KafkaBroker) and the types it hands out.
8///
9/// Underlying [`rdkafka`](https://docs.rs/rdkafka) errors are boxed as sources so the client
10/// library does not leak into this crate's public API surface.
11#[derive(Debug, Error)]
12#[non_exhaustive]
13pub enum KafkaError {
14    /// Creating a client failed or the cluster was unreachable during the connect probe.
15    #[error("kafka connection error: {0}")]
16    Connect(#[source] Box<dyn StdError + Send + Sync>),
17
18    /// Publishing a message failed or the broker did not confirm its delivery.
19    #[error("kafka publish error: {0}")]
20    Publish(#[source] Box<dyn StdError + Send + Sync>),
21
22    /// Creating a consumer or subscribing it to its topic failed.
23    #[error("kafka subscribe error: {0}")]
24    Subscribe(#[source] Box<dyn StdError + Send + Sync>),
25
26    /// Receiving a delivery from an open consumer failed.
27    #[error("kafka consume error: {0}")]
28    Consume(#[source] Box<dyn StdError + Send + Sync>),
29
30    /// A [`KafkaRetryPublisher`](crate::KafkaRetryPublisher) was used before its broker
31    /// connected.
32    ///
33    /// Only the early publisher can report this: it is the one handle minted before
34    /// [`Broker::connect`](ruststream::Broker::connect), for builder-time wiring that needs a
35    /// live publisher (`retry_via`). Everything on the policy path pairs with the connected
36    /// broker, so "not connected" is not representable there.
37    #[error("kafka broker is not connected yet; cannot reach {topic}")]
38    NotConnected {
39        /// The topic the operation targeted.
40        topic: String,
41    },
42
43    /// A handle aliasing the connection was used after the broker shut down.
44    ///
45    /// The lifecycle ladder makes misuse through the owner's handle a compile error:
46    /// [`ConnectedBroker::shutdown`](ruststream::ConnectedBroker::shutdown) consumes the
47    /// connected broker. Publishers paired off it earlier, and subscriptions still open, keep
48    /// aliasing the closed connection, so their operations report this instead of silently
49    /// succeeding against a dead connection.
50    #[error("kafka connection is closed; cannot reach {topic}")]
51    Closed {
52        /// The topic the operation targeted, or the transactional id of a transaction control
53        /// call.
54        topic: String,
55    },
56
57    /// The requested combination of options cannot be executed.
58    ///
59    /// The message names the offending option and the remediation.
60    #[error("invalid options: {0}")]
61    InvalidOptions(String),
62
63    /// `begin_transaction` found a transaction already open on this publisher.
64    ///
65    /// One producer runs one transaction at a time, so a second begin means two flows share
66    /// one publisher; erroring beats silently merging their messages into one transaction.
67    /// Concurrent transactional flows need distinct publishers - one per partition via
68    /// [`TransactionalPartitions`](crate::TransactionalPartitions), or distinct explicit ids.
69    #[error(
70        "a transaction is already open on publisher {id}; one publisher runs one transaction \
71         at a time - use distinct publishers (for example the per-partition set) for \
72         concurrent transactional flows"
73    )]
74    TransactionBusy {
75        /// The transactional id of the publisher that already has an open transaction.
76        id: String,
77    },
78
79    /// `commit` or `abort` was called with no transaction open on this publisher.
80    #[error("no transaction is open on publisher {id}; `begin_transaction` opens one")]
81    NoTransaction {
82        /// The transactional id of the publisher the call was made on.
83        id: String,
84    },
85
86    /// A Schema Registry request failed: unreachable registry, rejected credentials, an
87    /// unknown schema id or subject, or a schema the registry refused.
88    #[cfg(feature = "schema-registry")]
89    #[error("schema registry error: {0}")]
90    SchemaRegistry(#[source] Box<dyn StdError + Send + Sync>),
91}
92
93impl KafkaError {
94    pub(crate) fn connect(err: rdkafka::error::KafkaError) -> Self {
95        Self::Connect(Box::new(err))
96    }
97
98    pub(crate) fn publish(err: rdkafka::error::KafkaError) -> Self {
99        Self::Publish(Box::new(err))
100    }
101
102    #[cfg(feature = "schema-registry")]
103    pub(crate) fn schema_registry(err: impl StdError + Send + Sync + 'static) -> Self {
104        Self::SchemaRegistry(Box::new(err))
105    }
106
107    pub(crate) fn subscribe(err: rdkafka::error::KafkaError) -> Self {
108        Self::Subscribe(Box::new(err))
109    }
110
111    pub(crate) fn consume(err: rdkafka::error::KafkaError) -> Self {
112        Self::Consume(Box::new(err))
113    }
114}