EXC_BAD_INSTRUCTION when trying to print error from Swift 4 do-try-catch, skipping specified catch conditions - swift

I'm trying to catch my custom Error, but for some reason my catch statements where I name the error that I know is being thrown, it skips those, goes to the default catch, and then gives me a EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) when I try to do print("Unexpected error \(error)")
Here's some abbreviated code:
This is the error that I have declared in my file that houses the class that I'm calling the method on (the class is called CC8DB):
public enum CC8RSVPError: Error {
case noEventOnDate
case invalidRSVPValue
}
I have a method declared as:
public func rsvpForEvent(_ inEventDate:Date?, forUserID inUserID:String, withValue inRSVPValue:String) throws -> CC8RSVPStatus
In another class were I'm calling this method, I have this:
do {
let rsvpResponse = try self.cc8DB.rsvpForEvent(inRSVPDate, forUserID: String(inMessage.author.id.rawValue), withValue: inRSVPValue);
...(other code to do when this doesn't fail)...
} catch CC8RSVPError.invalidRSVPValue {
...(Report specific error to user)...
} catch CC8RSVPError.noEventOnDate {
...(Report specific error to user)...
} catch {
...(Report general error to user)...
print("Error doing RSVP: \(error)");
}
And finally, in the CC8DB.rsvpForEvent() method, I'm triggering an error that does this:
throw CC8RSVPError.invalidRSVPValue;
The germane part of this method is:
public func rsvpForEvent(_ inEventDate:Date?, forUserID inUserID:String, withValue inRSVPValue:String) throws -> CC8RSVPStatus
{
var retStatus = CC8RSVPStatus(eventDate: nil, previousRSVP: "", newRSVP: "");
var upperRSVPValue:String = inRSVPValue.uppercased();
if (["YES", "MAYBE", "NO"].contains(upperRSVPValue)) {
//...(Code to do things when the info is correct)...
} else {
throw CC8RSVPError.invalidRSVPValue;
}
return retStatus;
}
For my test case where I'm seeing this, the inRSVPValue is "bla", to test what happens when a user doesn't enter a valid status value.
What I'm seeing is that rather than going into the catch that's specific for the CC8RSVPError.invalidRSVPValue case, it's going down to the general catch. In addition, I'm getting the EXC_BAD_INSTRUCTION on the line where I try and print the error value.
I've stepped through it to verify that I am indeed hitting the throw line that I think I am, and I can see in the debugger that the value of error is CC8DB.CC8RSVPError.invalidRSVPValue, but even if I try to do po error from the lldb command, I get the same exception error.
Has anyone seen this or know what I could have done to make do-try-catch not work right?

You could assign a constant named error inside your catch statement and inside the catch block read the constant and figure out what to do with it.
do something like:
} catch let error {
switch error {
case CC8RSVPError.noEventOnDate:
// code
case CC8RSVPError.invalidRSVPValue:
// code
}
}

Ok, I figured it out. I realized that somewhere along the way, some build setting got set so that I was statically linking into the binary (this is a command-line tool, a bot for Discord to be specific).
I saw some warnings about some of the Swift runtime libs being found in both the binary and the XCode developer runtime area, and realized that it might be that the error object was being used both in my CC8DB module in the binary and in the built-modules folder (or something to that effect).
I need to statically link for when I actually deploy the bot to where it's going to run, so I must have turned something on that won't turn off (I deleted the extra flags that I thought turned that on, but that wasn't fixing it).
Basically, I recreated my .xcodeproj file with swift package generate-xcodeproj to clear out whatever I broke, and now it works as expected.
Thanks to everyone who looked at this and offered help (especially #gmogames for his time and help). I'm sure it helped lead me down the path of figuring this out.

Related

#GestureState cannot be used used as an attribute

In a project I want to declare a variable #GestureState, however I get the following error for no reason: "enum 'GestureState' cannot be used as an attribute".
I've worked with this kind of wrapper property before and didn't get this error at the time.
If anyone has an idea where this error might come from, I'll take it.
#GestureState var selected = false // error here :/
This happening because somewhere in the project you're creating an enum named GestureState rename it to something else and you're good to go.
Modify this:
enum GestureState { ... }
To this:
enum GestureStateType { ... }

PromiseKit, how to await a finalized promise?

coming from the JS world I'm having a bit of problem wrapping my head around promise kit flavor of promises, I need a bit of help with the following.
Assume I have a function that returns a promise, say an api call, on some super class I await for that promise, then do some other action (potentially another network call), on that parent call I also have a catch block in order to set some error flags for example, so in the end I have something close to this:
func apiCall() -> Promise<Void> {
return Promise { seal in
// some network code at some point:
seal.fulfill(())
}
}
// in another class/object
func doApiCall() -> ? { // catch forces to return PMKFinalizer
return apiCall()
.done {
// do something funky here
}
.catch {
print("Could not do first request"
}
}
now I'm trying to write some unit tests for this functionality, so the response is mocked and I know it will not fail, I just need to await so I can verify the internal state of my class:
// on my test file
doApiCall().done {
// test my code, but I get an error because I cannot pipe a promise that already has a `.catch`
}
How would one go about solving this problem? I could use finally to chain the PMKFinalizer but that feels wrong
Another tangential question would be, is it possible to re catch the error on a higher level, let's say a UI component so it can hold some temporary error state? as far as I see I did not see a way to achieve this.
Many thanks 🙏

Powershell bullet proof exception handling

I am migrating a very large function based script to classes, and trying to up my error trapping game at the same time. The code runs either on remote machines by way of jobs, or automatically & transparently at user logon, with log files the only means of communicating issues. The current (function based) version has some bugs that result in unhandled exceptions, which means the issues never make it into a log. The code reads a user provided XML file for data to process, and I need to provide meaningful feedback so that the data or data structure can be addressed. My goals in general are...
1: Catch ALL exceptions.
2: Visually differentiate between "expected" exceptions; where I provide some useful information in the log to allow the user to troubleshoot, and "unexpected" exceptions; where I provide script name and line number to help me track down bugs.
3: Over time move as many items as possible from "unexpected" to "expected".
Given those goals, there are a couple of things I am contemplating, and I feel like I don't know enough to be sure I am correct in my decision making.
1: $ErrorActionPreference=Stop Historically the advice has been NOT to set a global error action, and do it instead on a case by case basis. But given that every single situation where I CAN set it to stop I will, it seems like maybe this advice is really more about quick "scripts", whereas I am basically using PS to write a "program", and a global stop is the better answer?
2: Given a scenario like this, where I have an exception in a utility method (no I am not implementing a class here, I am trying to keep things simple for the example, but hopefully the concept is still clear)...
$path = '\\Server\InvalidFolder|'
try {
Test-Path $path -errorAction:stop
} catch [System.ArgumentException] {
throw [Custom.ExpectedException] "Error: Invalid characters in path - $invalidCharacters"
} catch {
# Generic error trap
throw [Custom.UnexpectedException] "Unexpected Error: $($_.ScriptStackTrace) $($_.Exception.Message)"
}
I feel like what I want/need to do is create some custom error types, so I can catch the different Powershell errors and convert them to my types, which I then throw, and the calling code has its own try/catch that then formats and pushes to the log. Is that the right approach, or am I missing some better option?
3: Assuming this is even possible/advisable, how does one create custom exception types? My Google-Fu has failed me and that has me wondering if I can't find anything because it can't/shouldn't be done.
EDIT: As far as the custom exception types go, this looks to work fine.
class PxException : Exception {
PxException() {
}
PxException([string] $message): base($message) {
}
PxException([string] $message, [Exception] $inner) : base($message, $inner) {
}
}
$path = '\\Server\InvalidFolder|'
try {
Test-Path $path -errorAction:stop
} catch [System.ArgumentException] {
Write-Host "Error: $($_.Exception.Message)"
throw [PxException] "Px expected exception"
} catch {
# Standard Px error trap
Write-Host "Unexpected Error: $($_.ScriptStackTrace)"
Write-Host "$($_.Exception.Message)"
}
Still wondering it it's the RIGHT way, but it is obviously A way, and that's a good sign.
EDIT 2: So, this works
class PxException : Exception {
PxException() {}
PxException([string] $message) : base($message) {}
PxException([string] $message, [Exception] $inner) : base($message, $inner) {}
}
But when I try to implement InvocationInfo in my custom type, it barfs...
class PxException : Exception {
PxException() {}
PxException([string] $message) : base($message) {}
PxException([string] $message, [InvocationInfo] $InvocationInfo) : base($message, $InvocationInfo) {}
PxException([string] $message, [Exception] $inner) : base($message, $inner) {}
}
[InvocationInfo] is not recognized as a type. Even if I have using namespace System;, which is where I think InvocationInfo is defined.
EDIT 3: GetType() to the rescue. This works.
PxException([string] $message, [System.Management.Automation.InvocationInfo] $InvocationInfo) : base($message, $InvocationInfo) {}
No using required. At least as far as getting rid of the error in the exception class definition. But
$InvocationInfo = $_.InvocationInfo
throw [PxException] "Px expected exception" $InvocationInfo
Does,'t work. Gotta figure out why I can't throw an exception with two arguments. But... progress.

How to determine what kind of error message I should return from golang API?

I have a GoLang API with an SPA to consume it. What I do to errors in my API is return them until the handler where I test if an error from previous functions exist. If there is an error, I put it inside the response body, set status code to either 400 or 500 then return the response
in the handler function, to be able to create a clear message to the client side, I need to know what kind of error was returned, how do I do it?
I know about error types but I read about Dave Cheney's recommendation to just return an error along with a message (or wrap them in other words).
But if there are so many kinds of errors which might occur in the API call, then does it mean before returning the response, I need to check them all just to know what message I should return?
The first thing to say about errors is that just because there's an error interface
type error interface {
Error() string
}
Does not mean that the error returned from any given method can only have that method / information attached to it.
One common method is to define your own error interface:
type myError interface {
error // embeds the standard error interface
OtherMethod() string // can define own methods here
}
When writing methods and functions it's really important to return an error and not myError, else you couple that method to your error implementation and cause dependency nightmares for yourself later.
Now that we've decided we can return extra information from error, using our own error interfaces you've got 3 main choices.
Sentinel errors
Error Failure types
Errors with Behaviour
Sentinel errors
Sentinel errors are error values that are defined as package level variables, are exported and allow comparison to check for errors.
package myPackage
var ErrConnectionFailed = errors.New("connection failed")
func Connect() error {
// trimmed ...
return ErrConnectionFailed
}
A consumer of this example could use the connect function:
if err := myPackage.Connect(); err == myPackage.ErrConnectionFailed {
// handle connection failed state
}
You can do a comparison to check if the error returned is equal to the sentinel error of the package. The drawback is that any error created with errors.New("connection failed") will be equal, and not just the error from myPackage.
Error failure types
Slightly better than sentinel errors are error failure types.
We've already seen that you can define your own error interface, and if we say ours is now:
type MyError interface {
error
Failure() string
}
type Err struct {
failure string
}
func (e *Err) Error() string {
// implement standard error
}
func (e *Err) Failure() string {
return e.failure
}
const ConnFailed = "connection failed"
err := &Err{failure: ConnFailed}
In the consumer code you can get an error, check if it implements MyError and then do things with it.
err := myPackage.Connect()
if myErr, ok := err.(myPackage.MyError); ok {
// here you know err is a MyError
if myErr.Failure() == myPackage.ConnFailed {
// handle connection failed, could also use a switch instead of if
}
}
Now you have an idea of what caused the error which is nice. But do you really care what the cause was? Or do you only really care what you want to do to handle that error.
This is where errors with behaviour are nice.
Errors with behaviour
This is similar to defining your own error type, but instead you define methods that report information about that error. Given the example above, do you really care that the connection failed, or do you really only care if you can retry or if you need to error up the call stack again?
package myPackage
// this interface could report if the error
// is temporary and if you could retry it
type tempErr interface {
Temporary() bool
}
func (e *Err) Temporary() bool {
// return if the error is temporary or not
}
Now in the consumer (note you don't need to use the myPackage.tempErr), you can test using type assertions if the error is temporary and handle the retry case:
err := myPackage.Connect()
if tmp, ok := err.(interface { Temporary() bool }); ok && tmp.Temporary() {
// the error is temporary and you can retry the connection
}
To answer the question, it's very hard to say without the specifics of the service that you are trying to implement. But as broad advice, I would try and use the last of the 3 examples as much as possible.
If the consumer of your service sends you some input that's not valid:
err := doThing(...)
if inv, ok := err.(interface { Invalid() bool }); ok && inv.Invalid() {
// input is invalid, return 400 bad request status code etc.
}
If you want to return a specific message to a consumer, you could make that a method of your error type. Warning: this would give your packages knowledge that they are being used in a web service, etc.
err := doThing(...)
if msg, ok := err.(interface { ResponseMsg() string }); ok {
// write the message to the http response
io.WriteString(response, msg.ResponseMsg())
}
TL;DR you would need to handle all the cases, but you can create error types that make the code much easier to work with!

"Useless expression" warning which I think is not correct

Consider following code sample:
def cleanUpAdvertiserInAdtech(name: String)(implicit driver: WebDriver):Unit = {
AdtechLoginPage.open
AdtechLoginPage.login
val attempt = Try {
AdtechDashboardPage.openAdvertisers
AdtechAdvertisersPage.deleteAdvertiserIfExists(name)
}
AdtechAdvertisersPage.logout
attempt.get
}
IntelliJ IDEA underlines the last line attempt.get and says that this is a useless expression. I am not sure I understand exactly why because this line just returns Unit in case when everything was nice in the Try{...} but throws an exception when something went wrong there.
Could you explain?
Because attempt.get not only will return Success value, it also will throw Failure exception:
If the Try.get return success value, attempt.get will return a success value, but it's never used. so this warning is correct to throw.
If the Try.get is failed,attempt.get will throw an Exception, the IDE warning is useless.
So I think IDE is correct to highlight this warning(IDE doesn't know whether will fail). you should change the Exception evaluate style, like use: match or try catch finally.