Skip to main content

tango/
error.rs

1//! The standard Tango error type.
2
3use std::fmt::{self, Debug, Display};
4use std::panic::Location;
5use std::borrow::Cow;
6use std::error;
7
8
9/// Type alias for a result with the standard [`Tango`] error type.
10pub type Result<T> = std::result::Result<T, Error>;
11
12/// A common error type for all Tango operations, which support metadata and easy to build
13/// chaining of errors.
14#[repr(transparent)]
15pub struct Error {
16    inner: Box<ErrorInner>,
17}
18
19#[derive(Debug)]
20struct ErrorInner {
21    /// The standardized reason of the error.
22    reason: Cow<'static, str>,
23    /// The human readable description of the error.
24    description: Cow<'static, str>,
25    /// The origin, in file/code, of the error.
26    origin: Cow<'static, str>,
27    /// The severity of the error.
28    severity: ErrorSeverity,
29    /// If thre reason was corresponding to a non-raw kind, then it's cached here.
30    kind: Option<ErrorKind<'static>>,
31    /// The source of the error.
32    source: Option<ErrorSource>,
33}
34
35#[derive(Debug)]
36enum ErrorSource {
37    /// The parent of the error is another Tango error.
38    Parent(Error),
39    /// A generic tango error.
40    Generic(Box<dyn error::Error + Send + Sync>),
41}
42
43impl From<std::convert::Infallible> for Error {
44    fn from(never: std::convert::Infallible) -> Self {
45        match never {}
46    }
47}
48
49impl Error {
50
51    /// Create a new error of the given kind, this will grab the origin of the error from
52    /// the caller's location. A default description is written depending on it by default,
53    /// you can append or replace this description later.
54    #[track_caller]
55    pub fn new(kind: ErrorKind<'_>) -> Self {
56        let mut ret = Self {
57            inner: Box::new(ErrorInner {
58                reason: Cow::Borrowed(""),
59                description: Cow::Borrowed(""),
60                origin: Cow::Borrowed(""),
61                severity: ErrorSeverity::Error,
62                kind: None,
63                source: None,
64            })
65        };
66        ret.set_kind(kind);
67        ret.set_origin_from_caller();
68        ret
69    }
70
71    pub(crate) fn not_implemented() -> Self {
72        Self::new(ErrorKind::NotImplemented)
73    }
74
75    /// Return the standardized textual reason.
76    pub fn reason(&self) -> &str {
77        &self.inner.reason
78    }
79
80    /// Get the kind of error, returning the raw reason if not categorized.
81    pub fn kind(&self) -> ErrorKind<'_> {
82        if let Some(kind) = self.inner.kind {
83            kind
84        } else {
85            ErrorKind::Reason(&self.inner.reason)
86        }
87    }
88
89    /// Change the kind of this error, this will also ensures that the associated reason
90    /// is correponding to the new error kind. If the description is empty at this point,
91    /// the description os overriden with a default description.
92    pub fn set_kind(&mut self, kind: ErrorKind<'_>) {
93        
94        // Only a fallback: an error that already says something specific keeps saying it.
95        if self.inner.description.is_empty() {
96            self.inner.description = Cow::Borrowed(kind.description());
97        }
98
99        let (reason, kind) = match kind.into_static() {
100            Ok(kind) => (Cow::Borrowed(kind.reason()), Some(kind)),
101            Err(kind) => (Cow::Owned(kind.reason().to_string()), None),
102        };
103
104        self.inner.kind = kind;
105        self.inner.reason = reason;
106
107    }
108
109    /// Change the kind of this error, and return itself.
110    pub fn with_kind(mut self, kind: ErrorKind<'_>) -> Self {
111        self.set_kind(kind);
112        self
113    }
114
115    /// Return the description of the error.
116    pub fn description(&self) -> &str {
117        &self.inner.description
118    }
119
120    /// Append the given additional description to the error's description, if the error
121    /// is currently empty, then this replaces the previous description. If a description
122    /// already exists, it appends the description on a new line.
123    pub fn append_description(&mut self, additional: impl Display) {
124        if self.inner.description.is_empty() {
125            self.inner.description = Cow::Owned(additional.to_string());
126        } else {
127            self.inner.description = Cow::Owned(format!("{}\n{additional}", self.inner.description));
128        }
129    }
130
131    /// Overwrite any existing description with the given one.
132    pub fn set_description(&mut self, description: impl Into<Cow<'static, str>>) {
133        self.inner.description = description.into();
134    }
135
136    /// Same as [`Self::append_description`], and return itself.
137    pub fn with_append_description(mut self, additional: impl Display) -> Self {
138        self.append_description(additional);
139        self
140    }
141
142    /// Overwrite any existing description with the given one, and return itself.
143    pub fn with_description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
144        self.set_description(description);
145        self
146    }
147
148    /// Return the severity of this error.
149    pub fn severity(&self) -> ErrorSeverity {
150        self.inner.severity
151    }
152
153    /// Set the severity of the error.
154    pub fn set_severity(&mut self, severity: ErrorSeverity) {
155        self.inner.severity = severity;
156    }
157
158    /// Set the severity of the error, and return itself.
159    pub fn with_severity(mut self, severity: ErrorSeverity) -> Self {
160        self.set_severity(severity);
161        self
162    }
163
164    /// Return the origin of this error, set by default to the caller's code location.
165    pub fn origin(&self) -> &str {
166        &self.inner.origin
167    }
168
169    /// Append the given additional origin to the existing origin, in order to add 
170    /// details, a space is added before insertion. If the origin has been replaced 
171    /// and is empty, then no space is added.
172    pub fn append_origin(&mut self, additional: impl Display) {
173        if self.inner.origin.is_empty() {
174            self.inner.origin = Cow::Owned(additional.to_string());
175        } else {
176            self.inner.origin = Cow::Owned(format!("{} {additional}", self.inner.origin));
177        }
178    }
179
180    /// Overwrite any existing origin with the given one.
181    pub fn set_origin(&mut self, origin: impl Into<Cow<'static, str>>) {
182        self.inner.origin = origin.into();
183    }
184
185    /// Same as [`Self::append_origin`], and return itself.
186    pub fn with_append_origin(mut self, additional: impl Display) -> Self {
187        self.append_origin(additional);
188        self
189    }
190
191    /// Overwrite any existing origin with the given one, and return itself.
192    pub fn with_origin(mut self, origin: impl Into<Cow<'static, str>>) -> Self {
193        self.set_origin(origin);
194        self
195    }
196
197    /// Overwrite the existing origin with the current location of the caller.
198    #[track_caller]
199    pub fn set_origin_from_caller(&mut self) {
200        let location = Location::caller();
201        self.set_origin(format!("{location}"));
202    }
203
204    /// Overwrite the existing origin with the current location of the caller, and return 
205    /// itself.
206    #[track_caller]
207    pub fn with_origin_from_caller(mut self) -> Self {
208        self.set_origin_from_caller();
209        self
210    }
211
212    /// If the source of this error is a parent Tango error, returns a shared ref to it.
213    /// To get a more generic source for this error, use the standard 
214    /// [`error::Error::source`] method.
215    pub fn parent(&self) -> Option<&Error> {
216        if let Some(ErrorSource::Parent(err)) = &self.inner.source {
217            Some(err)
218        } else {
219            None
220        }
221    }
222
223    /// Set the parent source of this error.
224    pub fn set_parent(&mut self, parent: Error) {
225        self.inner.source = Some(ErrorSource::Parent(parent));
226    }
227
228    /// Set the parent source of this error and return itself.
229    pub fn with_parent(mut self, parent: Error) -> Self {
230        self.set_parent(parent);
231        self
232    }
233
234    /// Set the generic source of this error.
235    pub fn set_source(&mut self, source: Box<dyn error::Error + Send + Sync>) {
236        self.inner.source = Some(ErrorSource::Generic(source));
237    }
238
239    /// Set the generic source of this error and return itself.
240    pub fn with_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
241        self.set_source(source);
242        self
243    }
244
245    /// A copy of this error and of its whole chain of parents, for an error that is handed
246    /// to several receivers. A generic source cannot be copied, so the copy has its text
247    /// alone as its source.
248    pub(crate) fn duplicate(&self) -> Self {
249
250        let source = match &self.inner.source {
251            Some(ErrorSource::Parent(err)) => Some(ErrorSource::Parent(err.duplicate())),
252            Some(ErrorSource::Generic(err)) => Some(ErrorSource::Generic(Box::new(std::io::Error::other(err.to_string())))),
253            None => None,
254        };
255
256        Self {
257            inner: Box::new(ErrorInner {
258                reason: self.inner.reason.clone(),
259                description: self.inner.description.clone(),
260                origin: self.inner.origin.clone(),
261                severity: self.inner.severity,
262                kind: self.inner.kind,
263                source,
264            }),
265        }
266
267    }
268
269}
270
271impl error::Error for Error {
272
273    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
274        match &self.inner.source {
275            Some(ErrorSource::Parent(err)) => Some(err),
276            Some(ErrorSource::Generic(err)) => Some(&**err),
277            None => None,
278        }
279    }
280
281}
282
283/// The whole chain of this error and its parents, on a single line, each error giving its
284/// reason and its description, escaped so that a description of several lines stays on
285/// that line: this is what a log line carries, see `{:#}` for what a person reads.
286///
287/// The alternate form gives an error per block, the origin of each of them along with
288/// it: a code location is noise in a log line, and the first thing wanted when debugging.
289impl Display for Error {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291
292        let separator = if f.alternate() { "\ncaused by " } else { " <- " };
293
294        let mut error = self;
295        loop {
296
297            let severity = match error.severity() {
298                ErrorSeverity::Warning => "WARNING",
299                ErrorSeverity::Error => "ERROR",
300                ErrorSeverity::Panic => "PANIC",
301            };
302
303            write!(f, "{severity}/{}", error.reason())?;
304
305            if !f.alternate() {
306                if !error.description().is_empty() {
307                    write!(f, "({:?})", error.description())?;
308                }
309            } else {
310                if !error.origin().is_empty() {
311                    write!(f, " @ {}", error.origin())?;
312                }
313                for line in error.description().lines() {
314                    write!(f, "\n  {line}")?;
315                }
316            }
317
318            match &error.inner.source {
319                Some(ErrorSource::Parent(parent)) => {
320                    f.write_str(separator)?;
321                    error = parent;
322                }
323                Some(ErrorSource::Generic(source)) => {
324                    // What is not a Tango error is told apart from one, being the cause of
325                    // the chain rather than a level of it.
326                    let mut source: &dyn error::Error = &**source;
327                    loop {
328                        write!(f, "{separator}{source}")?;
329                        match source.source() {
330                            Some(next) => source = next,
331                            None => break,
332                        }
333                    }
334                    break Ok(());
335                }
336                None => {
337                    break Ok(());
338                }
339            }
340
341        }
342
343    }
344}
345
346/// Written like [`Display`], within `Error(...)`: the derived struct dump is what a `main`
347/// returning a [`Result`] would otherwise print, and it is unreadable. The alternate form
348/// gives the alternate one of [`Display`], one error per block, with their origins.
349impl Debug for Error {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        if !f.alternate() {
352            write!(f, "Error({self})")
353        } else {
354            f.write_str("Error(\n")?;
355            for line in format!("{self:#}").lines() {
356                writeln!(f, "    {line}")?;
357            }
358            f.write_str(")")
359        }
360    }
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub enum ErrorKind<'r> {
365    /// For backends that could not handle a specific operation, this usually means to
366    /// fallback to the next backend to retry.
367    NotHandled,
368    /// For features that are not implemented.
369    NotImplemented,
370    // Database
371    TangoHostNotSet,
372    DatabaseNotConnected,
373    DatabaseNeeded,
374    AliasNotFound,
375    DevNotFound,
376    // Device
377    DevNotConnected,
378    // Server
379    ClassAlreadyDefined,
380    DevAlreadyDefined,
381    DevInitFailed,
382    CommandAlreadyDefined,
383    AttrAlreadyDefined,
384    // Class
385    ClassNotFound,
386    // Command
387    CommandNameInvalid,
388    CommandNotFound,
389    CommandArgumentKindInvalid,
390    // Attr
391    AttrNameInvalid,
392    AttrNotFound,
393    AttrNotWritable,
394    AttrKindInvalid,
395    // Event
396    EventNotConnected,
397    // Misc
398    InvalidIndex,
399    InvalidData,
400    InvalidProp,
401    TimedOut,
402    Corba,
403    Internal,
404    Reason(&'r str),
405}
406
407impl<'r> ErrorKind<'r> {
408
409    fn into_static(self) -> std::result::Result<ErrorKind<'static>, Self> {
410        Ok(match self {
411            ErrorKind::NotHandled => ErrorKind::NotHandled,
412            ErrorKind::NotImplemented => ErrorKind::NotImplemented,
413            ErrorKind::TangoHostNotSet => ErrorKind::TangoHostNotSet,
414            ErrorKind::DatabaseNotConnected => ErrorKind::DatabaseNotConnected,
415            ErrorKind::DatabaseNeeded => ErrorKind::DatabaseNeeded,
416            ErrorKind::AliasNotFound => ErrorKind::AliasNotFound,
417            ErrorKind::DevNotFound => ErrorKind::DevNotFound,
418            ErrorKind::DevNotConnected => ErrorKind::DevNotConnected,
419            ErrorKind::ClassAlreadyDefined => ErrorKind::ClassAlreadyDefined,
420            ErrorKind::DevAlreadyDefined => ErrorKind::DevAlreadyDefined,
421            ErrorKind::DevInitFailed => ErrorKind::DevInitFailed,
422            ErrorKind::CommandAlreadyDefined => ErrorKind::CommandAlreadyDefined,
423            ErrorKind::AttrAlreadyDefined => ErrorKind::AttrAlreadyDefined,
424            ErrorKind::ClassNotFound => ErrorKind::ClassNotFound,
425            ErrorKind::CommandNameInvalid => ErrorKind::CommandNameInvalid,
426            ErrorKind::CommandNotFound => ErrorKind::CommandNotFound,
427            ErrorKind::CommandArgumentKindInvalid => ErrorKind::CommandArgumentKindInvalid,
428            ErrorKind::AttrNameInvalid => ErrorKind::AttrNameInvalid,
429            ErrorKind::AttrNotFound => ErrorKind::AttrNotFound,
430            ErrorKind::AttrNotWritable => ErrorKind::AttrNotWritable,
431            ErrorKind::AttrKindInvalid => ErrorKind::AttrKindInvalid,
432            ErrorKind::EventNotConnected => ErrorKind::EventNotConnected,
433            ErrorKind::InvalidIndex => ErrorKind::InvalidIndex,
434            ErrorKind::InvalidData => ErrorKind::InvalidData,
435            ErrorKind::InvalidProp => ErrorKind::InvalidProp,
436            ErrorKind::TimedOut => ErrorKind::TimedOut,
437            ErrorKind::Corba => ErrorKind::Corba,
438            ErrorKind::Internal => ErrorKind::Internal,
439            ErrorKind::Reason(_) => return Err(self),
440        })
441    }
442
443    /// Return the textual and standard reason for this 
444    pub fn reason(&self) -> &'r str {
445        match self {
446            ErrorKind::NotHandled => reason::API_InternalError,
447            ErrorKind::NotImplemented => reason::API_InternalError,
448            ErrorKind::TangoHostNotSet => reason::API_TangoHostNotSet,
449            ErrorKind::DatabaseNotConnected => reason::API_CantConnectToDatabase,
450            ErrorKind::DatabaseNeeded => reason::API_InternalError,
451            ErrorKind::AliasNotFound => reason::API_AliasNotDefined,
452            ErrorKind::DevNotFound => reason::API_DeviceNotExported,
453            ErrorKind::DevNotConnected => reason::API_DeviceNotDefined,
454            ErrorKind::ClassAlreadyDefined => reason::API_InternalError,
455            ErrorKind::DevAlreadyDefined => reason::API_DeviceAlreadyDefined,
456            ErrorKind::DevInitFailed => reason::API_InitThrowsException,
457            ErrorKind::CommandAlreadyDefined => reason::API_InternalError,
458            ErrorKind::AttrAlreadyDefined => reason::API_InternalError,
459            ErrorKind::ClassNotFound => reason::API_ClassNotFound,
460            ErrorKind::CommandNameInvalid => reason::API_InternalError,
461            ErrorKind::CommandNotFound => reason::API_CommandNotFound,
462            ErrorKind::CommandArgumentKindInvalid => reason::API_IncompatibleCmdArgumentType,
463            ErrorKind::AttrNameInvalid => reason::API_InternalError,
464            ErrorKind::AttrNotFound => reason::API_AttrNotFound,
465            ErrorKind::AttrNotWritable => reason::API_AttrNotWritable,
466            ErrorKind::AttrKindInvalid => reason::API_IncompatibleAttrDataType,
467            ErrorKind::EventNotConnected => reason::API_EventNotFound,
468            ErrorKind::InvalidIndex => reason::API_InternalError,
469            ErrorKind::InvalidData => reason::API_InternalError,
470            ErrorKind::InvalidProp => reason::API_InternalError,
471            ErrorKind::TimedOut => reason::API_DeviceTimedOut,
472            ErrorKind::Corba => reason::API_CorbaException,
473            ErrorKind::Internal => reason::API_InternalError,
474            ErrorKind::Reason(reason) => reason,
475        }
476    }
477
478    /// Return a statically defined description of the error.
479    pub fn description(&self) -> &'static str {
480        match self {
481            ErrorKind::NotHandled => "The backend is not able to handle such request",
482            ErrorKind::NotImplemented => "This functionnality is not yet implemented",
483            ErrorKind::TangoHostNotSet => "The TANGO_HOST variable is not set, or its syntax is incorrect, it should hold a comma separated list of 'host:port'",
484            ErrorKind::DatabaseNotConnected => "Not able to connect to the Tango database",
485            ErrorKind::DatabaseNeeded => "This operation is only allowed if the device is connected through a database",
486            ErrorKind::AliasNotFound => "Alias was not found in the database",
487            ErrorKind::DevNotFound => "Device was not found in the database",
488            ErrorKind::DevNotConnected => "Device was not found on its device server",
489            ErrorKind::ClassAlreadyDefined => "Class is already defined on the server",
490            ErrorKind::DevAlreadyDefined => "Device is already defined on the server",
491            ErrorKind::DevInitFailed => "Device initialization failed",
492            ErrorKind::CommandAlreadyDefined => "Command is already defined in the device",
493            ErrorKind::AttrAlreadyDefined => "Attribute is already defined in the device",
494            ErrorKind::ClassNotFound => "Class was not found on the server",
495            ErrorKind::CommandNameInvalid => "Command name may contain invalid characters or is too long",
496            ErrorKind::CommandNotFound => "The command was not found on the device",
497            ErrorKind::CommandArgumentKindInvalid => "Invalid command argument data kind",
498            ErrorKind::AttrNameInvalid => "Attribute name may contain invalid characters or is too long",
499            ErrorKind::AttrNotFound => "The attribute was not found on the device",
500            ErrorKind::AttrNotWritable => "The attribute is not writable",
501            ErrorKind::AttrKindInvalid => "Invalid attribute data kind",
502            ErrorKind::EventNotConnected => "Not able to connect to an event for subscribing",
503            ErrorKind::InvalidIndex => "Invalid index for data",
504            ErrorKind::InvalidData => "Failed to handle data",
505            ErrorKind::InvalidProp => "Failed to handle property",
506            ErrorKind::TimedOut => "The network operation timed out",
507            ErrorKind::Corba => "An error happened in the CORBA backend",
508            ErrorKind::Internal => "Internal error in the library, this is most likely a bug",
509            ErrorKind::Reason(_) => "",
510        }
511    }
512
513}
514
515#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
516pub enum ErrorSeverity {
517    Warning,
518    Error,
519    Panic,
520}
521
522/// Standard device failed reasons, documented after their usage in cppTango and `Databaseds`;
523/// the ones noted as *not used by cppTango* only exist there as a constant.
524#[allow(non_upper_case_globals)]
525pub mod reason {
526
527    macro_rules! define_reasons {
528        ( $( $(#[$meta:meta])* $reason:ident ),* $(,)? ) => {
529            $( $(#[$meta])* pub const $reason: &str = stringify!($reason); )*
530        };
531    }
532
533    define_reasons![
534        /// The device or attribute alias is not defined in the database.
535        API_AliasNotDefined,
536        /// The command or attribute is already in the polling list of the device.
537        API_AlreadyPolled,
538        /// The reply of an asynchronous call has not arrived yet.
539        API_AsynReplyNotArrived,
540        /// Attribute configuration could not be read or applied.
541        API_AttrConfig,
542        /// Attribute event properties are wrong or cannot be set. Not used by cppTango.
543        API_AttrEventProp,
544        /// Wrapper reason stacked on the real error when reading or writing an attribute failed.
545        API_AttributeFailed,
546        /// A `data_ready` event was asked on an attribute not data ready enabled.
547        API_AttributeNotDataReadyEnabled,
548        /// An event was asked but the polling needed to push it is not started.
549        API_AttributePollingNotStarted,
550        /// Incorrect number of elements given when writing an attribute value.
551        API_AttrIncorrectDataNumber,
552        /// Alarm information was asked on an attribute which has no alarm defined.
553        API_AttrNoAlarm,
554        /// The attribute operation is forbidden, e.g. a property not changeable at run time.
555        API_AttrNotAllowed,
556        /// The attribute does not exist on the device or in its class.
557        API_AttrNotFound,
558        /// Attribute history or cached value was asked while the attribute is not polled.
559        API_AttrNotPolled,
560        /// A write was attempted on an attribute which is not `READ_WRITE`/`READ_WITH_WRITE`.
561        API_AttrNotWritable,
562        /// Problem with the attribute value or its optional properties: null pointer, bad type.
563        API_AttrOptProp,
564        /// The numeric representation of an attribute property value has not been set.
565        API_AttrPropValueNotSet,
566        /// The attribute value was never updated, it cannot be read nor pushed as an event.
567        API_AttrValueNotSet,
568        /// The attribute is badly defined in its class: bad data type, association, memorized.
569        API_AttrWrongDefined,
570        /// The memorized value stored in the database for this attribute has an incorrect format.
571        API_AttrWrongMemValue,
572        /// The asynchronous callback request being looked up does not exist.
573        API_BadAsyn,
574        /// Invalid asynchronous request identifier given for the polling model.
575        API_BadAsynPollId,
576        /// The asynchronous request type is incompatible with the call made on it.
577        API_BadAsynReqType,
578        /// A device configuration property has a wrong syntax, e.g. `polled_attr`.
579        API_BadConfigurationProperty,
580        /// The argument given to read the black box is out of range.
581        API_BlackBoxArgument,
582        /// Nothing is stored in the device black box yet.
583        API_BlackBoxEmpty,
584        /// The access control device could not be imported, rights cannot be checked.
585        API_CannotCheckAccessControl,
586        /// A file could not be opened, in cppTango the device server logging file.
587        API_CannotOpenFile,
588        /// Activation of the CORBA POA manager failed. Not used by cppTango.
589        API_CantActivatePOAManager,
590        /// The database device could not be reached on the given host and port.
591        API_CantConnectToDatabase,
592        /// The connection to the device could not be built, e.g. nil reference or dead server.
593        API_CantConnectToDevice,
594        /// Creation of the CORBA POA of a device class failed. Not used by cppTango.
595        API_CantCreateClassPoa,
596        /// The thread keeping a device lock alive could not be created.
597        API_CantCreateLockingThread,
598        /// The device to remove is not in the device list of its Tango class.
599        API_CantDestroyDevice,
600        /// No locking thread was found for that device, e.g. unlocking a non locked device.
601        API_CantFindLockingThread,
602        /// The client identification, required by the lock commands, could not be retrieved.
603        API_CantGetClientIdent,
604        /// The CORBA reference id of a device could not be obtained.
605        API_CantGetDevObjectId,
606        /// Installing a signal handler failed, bad signal number or OS error.
607        API_CantInstallSignal,
608        /// The addresses of a host could not be resolved. Specific to rstango: cppTango has
609        /// no such reason.
610        API_CantResolveHost,
611        /// The Tango class of a device could not be retrieved.
612        API_CantRetrieveClass,
613        /// The class list of a device server could not be retrieved. Not used by cppTango.
614        API_CantRetrieveClassList,
615        /// The device class could not be inserted in the client side class cache.
616        API_CantStoreDeviceClass,
617        /// The Tango class is not known by the device server process.
618        API_ClassNotFound,
619        /// The client Tango release is too old for events or device locking.
620        API_ClientTooOld,
621        /// The command argument data type is not handled by this code path.
622        API_CmdArgumentTypeNotSupported,
623        /// Command history or cached result was asked while the command is not polled.
624        API_CmdNotPolled,
625        /// Wrapper reason stacked on the real error when a `command_inout` failed.
626        API_CommandFailed,
627        /// The command is not allowed in the current device state.
628        API_CommandNotAllowed,
629        /// The command does not exist in the command list of the device class.
630        API_CommandNotFound,
631        /// A server side timeout expired on a serialization monitor or a blocked polling thread.
632        API_CommandTimedOut,
633        /// The network exchange with the device failed, wraps the transport error.
634        API_CommunicationFailed,
635        /// A connection to a peer failed, in cppTango the log consumer device.
636        API_ConnectionFailed,
637        /// A CORBA user exception was received and translated into a Tango error.
638        API_CorbaException,
639        /// A CORBA system exception was caught, an unexpected ORB or transport failure.
640        API_CorbaSysException,
641        /// The database returned inconsistent attribute or pipe properties.
642        API_CorruptedDatabase,
643        /// An error occurred while reading from or writing to the database.
644        API_DatabaseAccess,
645        /// The entry is not available from the database cache built at server startup.
646        API_DatabaseCacheAccess,
647        /// Error with the file database used in `-file=` mode: syntax, access or missing class.
648        API_DatabaseFileError,
649        /// Decoding of a `DevEncoded` payload failed.
650        API_DecodeErr,
651        /// Encoding of a `DevEncoded` payload failed.
652        API_EncodeErr,
653        /// A deprecated admin command was called, e.g. `SetTraceLevel`.
654        API_DeprecatedCommand,
655        /// The device is already defined in the database. Not used by cppTango.
656        API_DeviceAlreadyDefined,
657        /// The device is locked by another client, the request is refused.
658        API_DeviceLocked,
659        /// The device is not defined in the database, it cannot be imported.
660        API_DeviceNotDefined,
661        /// The device is defined but not exported, its device server is not running.
662        API_DeviceNotExported,
663        /// The device was not found in the device list of the server.
664        API_DeviceNotFound,
665        /// The operation requires the device to be locked first.
666        API_DeviceNotLocked,
667        /// The device, or one of its objects, is not polled.
668        API_DeviceNotPolled,
669        /// The client side timeout expired while waiting for the device answer.
670        API_DeviceTimedOut,
671        /// The device cannot be locked at all, e.g. the admin or database device.
672        API_DeviceUnlockable,
673        /// The lock owned on the device has been released, reported to its holder.
674        API_DeviceUnlocked,
675        /// The `DServer` class singleton is not initialised yet.
676        API_DServerClassNotInitialised,
677        /// The device server refused or failed the event registration.
678        API_DSFailedRegisteringEvent,
679        /// Placeholder reason with no meaning, used internally and never propagated.
680        API_DummyException,
681        /// The pipe data element is empty, it holds no value to extract.
682        API_EmptyDataElement,
683        /// The `DbDatum` holds no data, the requested extraction is impossible.
684        API_EmptyDbDatum,
685        /// Same as [`API_EmptyDbDatum`], kept because of a historical typo in cppTango.
686        API_EmptyDbDbDatum,
687        /// The `DeviceAttribute` holds no data, the read failed or it is uninitialised.
688        API_EmptyDeviceAttribute,
689        /// The `DeviceData` holds no data, the requested extraction is impossible.
690        API_EmptyDeviceData,
691        /// The notifd event channel could not be found, no notifd runs on that host.
692        API_EventChannelNotExported,
693        /// No event consumer object is available, no subscription was done before.
694        API_EventConsumer,
695        /// The given event id is unknown, on unsubscribe or event queue access.
696        API_EventNotFound,
697        /// The event properties needed by the requested event are not configured.
698        API_EventPropertiesNotSet,
699        /// Misuse of the event queue: none configured, or no event available to return.
700        API_EventQueues,
701        /// The event supplier of the server is not created yet.
702        API_EventSupplierNotConstructed,
703        /// No event was received within the keep alive period, pushed to the callback.
704        API_EventTimeout,
705        /// Internal inconsistency in the forwarded attribute registry maps.
706        API_FwdAttrInconsistency,
707        /// The forwarded attribute has no valid root. Not used by cppTango, see [`API_AttrConfig`].
708        API_FwdAttrNotConfigured,
709        /// The history data received is invalid, its format could not be interpreted.
710        API_HistoryInvalid,
711        /// The data received from the database device is not what the client expected.
712        API_IncoherentDbData,
713        /// The data received from the device is not coherent with the type extracted.
714        API_IncoherentDevData,
715        /// Two related property values are incoherent, e.g. `min` greater than `max`.
716        API_IncoherentValues,
717        /// The argument type is incompatible with the target type, e.g. for an enum.
718        API_IncompatibleArgumentType,
719        /// The extracted type does not match the `DeviceAttribute` content.
720        API_IncompatibleAttrArgumentType,
721        /// The provided value data type does not match the attribute data type.
722        API_IncompatibleAttrDataType,
723        /// The command argument type does not match the type the command expects.
724        API_IncompatibleCmdArgumentType,
725        /// No `init_device` method found for the class. Not used by cppTango.
726        API_InitMethodNotFound,
727        /// The `init_device` method is not public and cannot be called. Not used by cppTango.
728        API_InitNotPublic,
729        /// `init_device()` threw, so the device is no longer available.
730        API_InitThrowsException,
731        /// Unexpected internal state of the library, and generic fallback reason.
732        API_InternalError,
733        /// An invalid argument was given to a library call or on the server command line.
734        API_InvalidArgs,
735        /// The received CORBA `Any` has an unexpected kind and cannot be interpreted.
736        API_InvalidCorbaAny,
737        /// A Java runtime security error occurred. JTango only.
738        API_JavaRuntimeSecurityException,
739        /// Writing a memorized attribute failed during the device startup sequence.
740        API_MemAttFailedDuringInit,
741        /// A memory allocation failed in the server or in the client.
742        API_MemoryAllocation,
743        /// A method argument is missing, of the wrong type, or in the wrong number.
744        API_MethodArgument,
745        /// The requested method was not found. JTango and PyTango only.
746        API_MethodNotFound,
747        /// Some events were lost, e.g. ZMQ high water mark reached, pushed to the callback.
748        API_MissedEvents,
749        /// Polling is configured but its cache holds no data yet for that object.
750        API_NoDataYet,
751        /// The method requires a database, but the device was built without one.
752        API_NonDatabaseDevice,
753        /// No write (set) value is available in the `DeviceAttribute`.
754        API_NoSetValueAvailable,
755        /// The notifd notification service failed, e.g. its factory import.
756        API_NotificationServiceFailed,
757        /// The operation is not supported in this context, e.g. polling not externally triggered.
758        API_NotSupported,
759        /// The peer does not support the feature, its IDL release is too old.
760        API_NotSupportedFeature,
761        /// The polling cache data is not refreshed any more, polling stopped or in error.
762        API_NotUpdatedAnyMore,
763        /// Creation of the Windows debug or main output window failed.
764        API_NtDebugWindowError,
765        /// Command or method overloading is not supported. PyTango and JTango only.
766        API_OverloadingNotSupported,
767        /// Data element not found in the pipe blob. Not used by cppTango, see [`API_PipeWrongArg`].
768        API_PipeDataEltNotFound,
769        /// Two data elements of the same pipe blob have the same name.
770        API_PipeDuplicateDEName,
771        /// Wrapper reason stacked on the real error when reading or writing a pipe failed.
772        API_PipeFailed,
773        /// No data element is available in the pipe blob for insertion or extraction.
774        API_PipeNoDataElement,
775        /// Reading or writing the pipe is currently not allowed, e.g. by the serial model.
776        API_PipeNotAllowed,
777        /// The pipe does not exist on the device or in its class.
778        API_PipeNotFound,
779        /// A write was attempted on a pipe which is not writable.
780        API_PipeNotWritable,
781        /// Problem with a pipe data element property, e.g. a null data pointer.
782        API_PipeOptProp,
783        /// The pipe value was never updated by the device, it cannot be read.
784        API_PipeValueNotSet,
785        /// Wrong argument used on a pipe blob: bad index, bad data type, or blob never received.
786        API_PipeWrongArg,
787        /// Wrong number of data elements given for a pipe. Not used by cppTango.
788        API_PipeWrongArgNumber,
789        /// The polling pool is full and the device is not in the pool configuration.
790        API_PolledDeviceNotInPoolConf,
791        /// The polling pool is full and the device is missing from the polled map.
792        API_PolledDeviceNotInPoolMap,
793        /// No polling thread was found for that device or thread id.
794        API_PollingThreadNotFound,
795        /// The command or attribute is not in the polled object list of the device.
796        API_PollObjNotFound,
797        /// Not enough data is stored yet in the polling ring buffer.
798        API_PollRingBufferEmpty,
799        /// The polling thread lost its schedule and is out of sync.
800        API_PollThreadOutOfSync,
801        /// Access control refused the request, the client only has read access.
802        API_ReadOnlyMode,
803        /// Root attribute access failed. Not used by cppTango, see [`API_AttributeFailed`].
804        API_RootAttrFailed,
805        /// The device server process is not running, reported without database.
806        API_ServerNotRunning,
807        /// The device server is shutting down and refuses the request.
808        API_ShutdownInProgress,
809        /// The signal number is out of range or cannot be handled by a user handler.
810        API_SignalOutOfRange,
811        /// An error occurred in the device server startup sequence.
812        API_StartupSequence,
813        /// A `std::exception` was caught and translated into a Tango error.
814        API_StdException,
815        /// A system call failed, e.g. socket creation or `getifaddrs()`.
816        API_SystemCallFailed,
817        /// The `TANGO_HOST` variable is not set, or its syntax is incorrect.
818        API_TangoHostNotSet,
819        /// Generic reason for an exception thrown on purpose. Not used by cppTango.
820        API_ThrowException,
821        /// The attribute is not supported by the device.
822        API_UnsupportedAttribute,
823        /// Unsupported database modifier in a name, only `#dbase=no|yes` are valid.
824        API_UnsupportedDBaseModifier,
825        /// The feature is absent from this build, e.g. a Tango built without jpeg.
826        API_UnsupportedFeature,
827        /// Unsupported protocol prefix in a name, only `tango://` is supported.
828        API_UnsupportedProtocol,
829        /// The `Util` singleton is not created, Tango is not initialised.
830        API_UtilSingletonNotCreated,
831        /// The `Util` singleton was inherited through a `fork()` without `exec()`.
832        API_UtilSingletonPoisoned,
833        /// The written value is outside the attribute limits, or is NaN/Inf, or too large.
834        API_WAttrOutsideLimit,
835        /// A property is already defined in the wizard configuration of the class.
836        API_WizardConfError,
837        /// Invalid attribute name syntax, four fields or a plain alias are expected.
838        API_WrongAttributeNameSyntax,
839        /// Wrong command line arguments given to the device server.
840        API_WrongCmdLineArgs,
841        /// Invalid device name syntax, `domain/family/member` is expected.
842        API_WrongDeviceNameSyntax,
843        /// The event data received is malformed and cannot be turned into a value.
844        API_WrongEventData,
845        /// The `DevEncoded` data is not in the expected image format.
846        API_WrongFormat,
847        /// The history data buffer received from the server is not valid.
848        API_WrongHistoryDataBuffer,
849        /// The locking status returned by the server is invalid.
850        API_WrongLockingStatus,
851        /// Wrong number of arguments given to a command, mostly the admin ones.
852        API_WrongNumberOfArgs,
853        /// Wrong use of wildcards in a pattern, only one `*` is allowed.
854        API_WrongWildcardUsage,
855        /// A ZMQ call failed at run time, when binding or pushing an event or heartbeat.
856        API_ZmqFailed,
857        /// ZMQ initialisation failed, on context creation or socket bind at startup.
858        API_ZmqInitFailed,
859        /// `Databaseds`: no alias for that device/attribute, or nothing matches that alias.
860        DB_AliasNotDefined,
861        /// The Tango class was not found in the startup database cache.
862        DB_ClassNotFoundInCache,
863        /// `Databaseds`: device, server, event or class not defined in the database.
864        DB_DeviceNotDefined,
865        /// The device or object was not found in the startup database cache.
866        DB_DeviceNotFoundInCache,
867        /// `Databaseds`: a MySQL query, a stored procedure or the given SQL command failed.
868        DB_SQLError,
869        /// The database stored procedure is too old, e.g. pipes need release 1.9.
870        DB_TooOldStoredProc,
871    ];
872
873}