Skip to main content

tango/
error.rs

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