irontide_session/error.rs
1/// Convenience alias for `Result<T, Error>`.
2pub type Result<T> = std::result::Result<T, Error>;
3
4/// Errors that can occur during session operations.
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7 /// Wire protocol error from the peer connection layer.
8 #[error("wire: {0}")]
9 Wire(#[from] irontide_wire::Error),
10
11 /// Storage/disk I/O error.
12 #[error("storage: {0}")]
13 Storage(#[from] irontide_storage::Error),
14
15 /// Tracker communication error.
16 #[error("tracker: {0}")]
17 Tracker(#[from] irontide_tracker::Error),
18
19 /// DHT operation error.
20 #[error("DHT: {0}")]
21 Dht(#[from] irontide_dht::Error),
22
23 /// Core library error (metainfo parsing, hashing, etc.).
24 #[error("core: {0}")]
25 Core(#[from] irontide_core::Error),
26
27 /// Peer connection failed.
28 #[error("connection: {0}")]
29 Connection(
30 /// Error description.
31 String,
32 ),
33
34 /// Received metadata whose info hash does not match the expected value.
35 #[error("metadata info_hash mismatch")]
36 MetadataHashMismatch,
37
38 /// A piece failed hash verification.
39 #[error("piece {index} hash verification failed")]
40 PieceHashFailed {
41 /// Zero-based piece index that failed verification.
42 index: u32,
43 },
44
45 /// Received invalid peer data from a tracker or PEX message.
46 #[error("invalid peer data: {0}")]
47 InvalidPeerData(
48 /// Description of the invalid data.
49 String,
50 ),
51
52 /// The requested torrent is not in the session.
53 #[error("torrent not found: {0}")]
54 TorrentNotFound(
55 /// Info hash of the missing torrent.
56 irontide_core::Id20,
57 ),
58
59 /// Attempted to add a torrent that already exists in the session.
60 #[error("duplicate torrent: {0}")]
61 DuplicateTorrent(
62 /// Info hash of the duplicate torrent.
63 irontide_core::Id20,
64 ),
65
66 /// The session has reached its maximum torrent capacity.
67 #[error("session at capacity ({0} torrents)")]
68 SessionAtCapacity(
69 /// Current number of torrents in the session.
70 usize,
71 ),
72
73 /// Torrent metadata has not been received yet (magnet link still resolving).
74 #[error("metadata not yet available for {0}")]
75 MetadataNotReady(
76 /// Info hash of the torrent awaiting metadata.
77 irontide_core::Id20,
78 ),
79
80 /// File index is out of range for the torrent.
81 #[error("file index {index} out of range (torrent has {count} files)")]
82 InvalidFileIndex {
83 /// The requested file index.
84 index: usize,
85 /// Total number of files in the torrent.
86 count: usize,
87 },
88
89 /// Attempted to stream a file that has `Skip` priority.
90 #[error("file has Skip priority (index {index})")]
91 FileSkipped {
92 /// The file index with `Skip` priority.
93 index: usize,
94 },
95
96 /// Piece index is out of range for the torrent.
97 #[error("piece index {index} out of range (torrent has {num_pieces} pieces)")]
98 InvalidPieceIndex {
99 /// The requested piece index.
100 index: u32,
101 /// Total number of pieces in the torrent.
102 num_pieces: u32,
103 },
104
105 /// Configuration error (e.g. invalid proxy settings).
106 #[error("configuration error: {0}")]
107 Config(
108 /// Error description.
109 String,
110 ),
111
112 /// Settings validation failed.
113 #[error("invalid settings: {0}")]
114 InvalidSettings(
115 /// Description of the invalid setting.
116 String,
117 ),
118
119 /// The session is shutting down and cannot accept new commands.
120 #[error("session shutting down")]
121 Shutdown,
122
123 /// DHT is disabled in session settings.
124 #[error("DHT is disabled")]
125 DhtDisabled,
126
127 /// Peer read timeout — no wire message received within the configured duration.
128 #[error("peer read timeout ({0}s)")]
129 PeerReadTimeout(
130 /// Configured timeout in seconds.
131 u64,
132 ),
133
134 /// Peer data contribution timeout — no Piece message received within the configured duration.
135 #[error("peer data timeout ({0}s)")]
136 PeerDataTimeout(
137 /// Configured timeout in seconds.
138 u64,
139 ),
140
141 /// Peer write timeout — outgoing message could not be sent within the configured duration.
142 #[error("peer write timeout ({0}s)")]
143 PeerWriteTimeout(
144 /// Configured timeout in seconds.
145 u64,
146 ),
147
148 /// M182: per-channel backpressure queue exceeded its cap. Treated
149 /// as a soft stall — the downstream consumer (requester or
150 /// `TorrentActor`) is too slow and the wire reader would otherwise
151 /// stall TCP for all peers on this connection. See M182 audit
152 /// `docs/investigations/2026-05-02-m182-stall-audit/INVESTIGATION.md`.
153 #[error("peer backpressure overflow ({0})")]
154 PeerBackpressureOverflow(
155 /// Channel name (`dispatch_tx` or `event_tx`).
156 &'static str,
157 ),
158
159 /// I2P SAM protocol error.
160 #[error("I2P: {0}")]
161 I2p(#[from] crate::i2p::SamError),
162
163 /// Operating system I/O error.
164 #[error("I/O: {0}")]
165 Io(#[from] std::io::Error),
166
167 /// M170: caller specified a category that is not in the registry.
168 /// The qBt API maps this to 409 Conflict.
169 #[error("category not found: {0}")]
170 CategoryNotFound(
171 /// The unknown category name.
172 String,
173 ),
174
175 /// M170: an add arrived while the same info hash is still being
176 /// removed by a `deleteFiles=true` delete. Caller should retry
177 /// shortly. Mapped to 409 Conflict by the qBt API.
178 #[error("torrent is being removed, retry later")]
179 TorrentBeingRemoved(
180 /// Info hash currently in the delete grace period.
181 irontide_core::Id20,
182 ),
183
184 /// M170: category registry persistence error.
185 #[error("category registry: {0}")]
186 CategoryRegistry(
187 /// Error description from the category manager.
188 String,
189 ),
190
191 /// M173 Lane B (B11): a concurrent `apply_settings` call won the
192 /// in-flight guard; this caller must retry shortly. The qBt v2
193 /// `setPreferences` handler maps this to HTTP 409 Conflict.
194 #[error("apply_settings: concurrent reconfig in flight, retry shortly")]
195 ConcurrentReconfig,
196}