ASCOM's Application Programming Interfaces (APIs) incorporate the fundamental programming principle of "Do it right or raise an exception". If you need to refresh your understanding of this principle and its consequences, please use the preceding link then come back here to understand the details of exceptions within the ASCOM COM and ASCOM Alpaca environment.
All modern languages and run time environments use "out of band" exception reporting and handling [*]. By out of band is meant that upon an error condition being detected or reported (an "exceptional" condition), the normal program execution flow is interrupted, and execution resumes somewhere else in some sort of pre-arranged error handling code. This goes back as far as the original C language which has setjmp/longjmp ("hack the stack and go back Jack!") which is an out of band exception system. Unix "signals" are another example.
Virtually all popular languages use Structured Exception Handling. Most commonly this consists of a special statement like throw orIn modular systems where a program may be using a 3rd party package, library, or a separate process, or in a system like Python or Node.js where packages are widely used, it's often essential that the name of the source of the exception be part of the packaged info. Furthermore in some languages, it is possible for the exception package to contain an entire embedded exception package ("inner exception") that may originate in a downstream or sub-module.
For example, your code makes a call to a local library and that library makes a call to an endpoint on another system. On the remote device an error occurs and the local library receives an error response. The library function you called has now failed and must raise an exception. The exception source would be the library you called, and the details might include a message that a call to a particular endpoint (one of several possibilities) failed and the details should describe the consequences of that failure to the library. That exception package could (should) include an inner exception whose source is the lower-level API itself, and message indicating what went wrong over on the device's server, and ideally why.
Finally some programming environments (e.g. C# and Java) support multiple types of exceptions and separate multiple individual catch(exception-type ex) error handling blocks for each type of exception.
Applications must be prepared to catch exceptions from any Alpaca endpoint or ASCOM COM property or method, including Completion Properties for (asynchronous) ASCOM methods. This should go without saying since anyone who writes software in a modern language and ecosystem needs to be prepared for run time errors and exceptions. Unfortunately, writing software to control physical devices (mounts, domes, etc) needs to be prepared for exceptions because those physical devices (and ther connections like USB) are much more susceptible to error states compared to pure code.
This includes both Alpaca and COM. Both method calls and completion properties may raise exceptions. In COM the exception is a true run-time error. WIth Alpaca, the exception comes back as a JSON object with non-zero ErrorNumber and non-null ErrorMessage. A simple exception in Alpaca is this one coming from a mount that cannot slew when sidereal tracking is false.
{
"ClientTransactionID":4531,
"ServerTransactionID":4527,
"ErrorNumber":1035,
"ErrorMessage":""SlewToCoordinatesAsync is not allowed when tracking is False"
}
Exceptions aren't always this simple. Be prepared for an Alpaca response like this. This is the same exception but from the ASCOM COM Telescope Simulator.NET, converted into an Alpaca exception by ASCOM Remote. This is an extreme example. The point here is that you need to be prepared for anything that is a legal exception. Note that if you wish, you can ignore the DriverException field of the Alpaca JSON response object if you don't think your users would care. In any case the key is that there is a non-zero ErrorNumber, and a non-null Error Message. Be sure to report the primary error to your user!
{
"ClientTransactionID":26243,
"ServerTransactionID":310,
"ErrorNumber":1035,
"ErrorMessage":"SlewToCoordinatesAsync is not allowed when tracking is False",
"DriverException":{
"ClassName":"System.Runtime.InteropServices.COMException",
"Message":"SlewToCoordinatesAsync is not allowed when tracking is False",
"Data":null,
"InnerException":null,
"HelpURL":null,
"StackTraceString":" at System.Dynamic.ComRuntimeHelpers.CheckThrowException(Int32 hresult, ExcepInfo& excepInfo, UInt32 argErr, String message)\r\n at CallSite.Target(Closure , CallSite , ComObject , Double , Double )\r\n at CallSite.Target(Closure , CallSite , Object , Double , Double )\r\n at ASCOM.Remote.ServerForm.CallMethod(String deviceType, RequestData requestData) in J:\\ASCOMRemote\\Remote Server\\ServerForm.cs:line 5792",
"RemoteStackTraceString":null,
"RemoteStackIndex":0,
"ExceptionMethod":"8\nCheckThrowException\nSystem.Dynamic, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\nSystem.Dynamic.ComRuntimeHelpers\nVoid CheckThrowException(Int32, System.Dynamic.ExcepInfo ByRef, UInt32, System.String)",
"HResult":-2147220469,
"Source":"ASCOM.Simulator.Telescope",
"WatsonBuckets":null
}
}
If you get something like this from an Alpaca end point, you should consider this just like an out-of-band run time error raised by the Alpaca-speaking device.