fidl/
error.rs

1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Error (common to all fidl operations)
6
7use crate::handle::{ObjectType, Rights};
8use std::sync::Arc;
9use zx_status::Status;
10
11/// A specialized `Result` type for FIDL operations.
12pub type Result<T, E = Error> = std::result::Result<T, E>;
13
14#[derive(Debug, Clone, thiserror::Error)]
15#[allow(missing_docs)]
16pub enum TransportError {
17    #[error(transparent)]
18    Status(#[from] Status),
19    #[error(transparent)]
20    Other(Arc<dyn std::error::Error + Send + Sync>),
21}
22
23// This prevents some binary size bloat.
24impl Drop for TransportError {
25    #[inline(never)]
26    fn drop(&mut self) {}
27}
28
29/// The error type used by FIDL operations.
30#[derive(Debug, Clone, thiserror::Error)]
31#[non_exhaustive]
32#[allow(missing_docs)]
33pub enum Error {
34    #[error("Unexpected response to synchronous FIDL query.")]
35    UnexpectedSyncResponse,
36
37    #[error("Invalid FIDL boolean.")]
38    InvalidBoolean,
39
40    #[error("Invalid header for a FIDL buffer.")]
41    InvalidHeader,
42
43    #[error("Incompatible wire format magic number: {0}.")]
44    IncompatibleMagicNumber(u8),
45
46    #[error("Unsupported wire format version")]
47    UnsupportedWireFormatVersion,
48
49    #[error("Invalid FIDL buffer.")]
50    Invalid,
51
52    #[error("The FIDL object could not fit within the provided buffer range")]
53    OutOfRange,
54
55    #[error("Decoding the FIDL object did not use all of the bytes provided.")]
56    ExtraBytes,
57
58    #[error("Decoding the FIDL object did not use all of the handles provided.")]
59    ExtraHandles,
60
61    #[error(
62        "Decoding the FIDL object observed non-zero value in the padding region \
63        starting at byte {padding_start}."
64    )]
65    NonZeroPadding {
66        /// Index of the first byte of the padding, relative to the beginning of the message.
67        padding_start: usize,
68    },
69
70    #[error("The FIDL object had too many layers of out-of-line recursion.")]
71    MaxRecursionDepth,
72
73    #[error(
74        "There was an attempt to read or write a null-valued object as a non-nullable FIDL type."
75    )]
76    NotNullable,
77
78    #[error("A FIDL object reference with nonzero byte length had a null data pointer.")]
79    UnexpectedNullRef,
80
81    #[error("A FIDL message contained incorrectly encoded UTF8.")]
82    Utf8Error,
83
84    #[error("Vector was too long. Expected at most {max_length} elements, got {actual_length}.")]
85    VectorTooLong {
86        /// Maximum length, i.e. the `N` in `vector<T>:N`.
87        max_length: usize,
88        /// Actual length of the vector (number of elements).
89        actual_length: usize,
90    },
91
92    #[error("String was too long. Expected at most {max_bytes} bytes, got {actual_bytes}.")]
93    StringTooLong {
94        /// Maximum length in bytes, i.e. the `N` in `string:N`.
95        max_bytes: usize,
96        /// Actual length of the string in bytes.
97        actual_bytes: usize,
98    },
99
100    #[error(
101        "A message was received for ordinal value {ordinal} that the FIDL \
102        protocol {protocol_name} does not understand."
103    )]
104    UnknownOrdinal { ordinal: u64, protocol_name: &'static str },
105
106    #[error(
107        "Server for the FIDL protocol {protocol_name} did not recognize method {method_name}."
108    )]
109    UnsupportedMethod { method_name: &'static str, protocol_name: &'static str },
110
111    #[error("Invalid bits value for a strict bits type.")]
112    InvalidBitsValue,
113
114    #[error("Invalid enum value for a strict enum type.")]
115    InvalidEnumValue,
116
117    #[error("Unrecognized descriminant for a FIDL union type.")]
118    UnknownUnionTag,
119
120    #[error("A FIDL future was polled after it had already completed.")]
121    PollAfterCompletion,
122
123    #[error(
124        "Received request with zero txid for two-way method ordinal, \
125        or nonzero txid for one-way method ordinal."
126    )]
127    InvalidRequestTxid,
128
129    #[error("Received response with unknown txid.")]
130    InvalidResponseTxid,
131
132    #[error("Received response with unexpected ordinal.")]
133    InvalidResponseOrdinal,
134
135    #[error("Invalid presence indicator.")]
136    InvalidPresenceIndicator,
137
138    #[error("Invalid inline bit in envelope.")]
139    InvalidInlineBitInEnvelope,
140
141    #[error("Invalid inline marker in envelope.")]
142    InvalidInlineMarkerInEnvelope,
143
144    #[error("Invalid number of bytes in FIDL envelope.")]
145    InvalidNumBytesInEnvelope,
146
147    #[error("Invalid number of handles in FIDL envelope.")]
148    InvalidNumHandlesInEnvelope,
149
150    #[error("Invalid FIDL handle used on the host.")]
151    InvalidHostHandle,
152
153    #[error("Incorrect handle subtype. Expected {}, but received {}", .expected.into_raw(), .received.into_raw())]
154    IncorrectHandleSubtype { expected: ObjectType, received: ObjectType },
155
156    #[error("Some expected handle rights are missing: {}", .missing_rights.bits())]
157    MissingExpectedHandleRights { missing_rights: Rights },
158
159    #[error("An error was encountered during handle replace()")]
160    HandleReplace(#[source] Status),
161
162    #[error("A server encountered an IO error writing a FIDL response to a channel: {0}")]
163    ServerResponseWrite(#[source] TransportError),
164
165    #[error(
166        "A FIDL server encountered an IO error reading incoming FIDL requests from a channel: {0}"
167    )]
168    ServerRequestRead(#[source] TransportError),
169
170    #[error("A FIDL server encountered an IO error writing an epitaph into a channel: {0}")]
171    ServerEpitaphWrite(#[source] TransportError),
172
173    #[error("A FIDL client encountered an IO error reading a response from a channel: {0}")]
174    ClientRead(#[source] TransportError),
175
176    #[error("A FIDL client encountered an IO error writing a request into a channel: {0}")]
177    ClientWrite(#[source] TransportError),
178
179    #[error("A FIDL client encountered an IO error issuing a channel call: {0}")]
180    ClientCall(#[source] Status),
181
182    #[error("A FIDL client encountered an IO error issuing a channel call: {0}")]
183    ClientEvent(#[source] Status),
184
185    #[cfg(not(target_os = "fuchsia"))]
186    #[error("A FIDL client's channel to the protocol {protocol_name} was closed: {status}, reason: {}",
187        .reason.as_ref().map(String::as_str).unwrap_or("not given")
188    )]
189    ClientChannelClosed {
190        /// The epitaph or `Status::PEER_CLOSED`.
191        #[source]
192        status: Status,
193        /// The name of the protocol at the other end of the channel.
194        protocol_name: &'static str,
195        /// The epitaph, if any. This can be used to discriminate channel closure with a
196        /// `Status::PEER_CLOSED` epitaph from a channel closure with no epitaph. Note that here,
197        /// the epitaph is treated as an opaque 32-bit integer.
198        epitaph: Option<u32>,
199        /// Further details on why exactly the channel closed.
200        reason: Option<String>,
201    },
202
203    #[cfg(target_os = "fuchsia")]
204    #[error("A FIDL client's channel to the protocol {protocol_name} was closed: {status}")]
205    ClientChannelClosed {
206        /// The epitaph or `Status::PEER_CLOSED`.
207        #[source]
208        status: Status,
209        /// The name of the protocol at the other end of the channel.
210        protocol_name: &'static str,
211        /// The epitaph, if any. This can be used to discriminate channel closure with a
212        /// `Status::PEER_CLOSED` epitaph from a channel closure with no epitaph. Note that here,
213        /// the epitaph is treated as an opaque 32-bit integer.
214        epitaph: Option<u32>,
215    },
216
217    #[error("There was an error attaching a FIDL channel to the async executor: {0}")]
218    AsyncChannel(#[source] Status),
219
220    #[cfg(target_os = "fuchsia")]
221    #[cfg(test)]
222    #[error("Test Status: {0}")]
223    TestIo(#[source] Status),
224}
225
226impl Error {
227    /// Returns `true` if the error was sourced by a closed channel.
228    pub fn is_closed(&self) -> bool {
229        matches!(self, Error::ClientChannelClosed { .. })
230    }
231}