Not sure if my approach is correct catch and throw error (NSError.debugDescription crash)

Hi,

I have an logging function which logs when an error occurs.

My logging function seems to crash the app.

Exception: Thread 10: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Error that was being logged: Core data error when a non-nil field is trying to be saved with a nil value

private static func logText(fromNSError error: NSError) -> String {
    
    var log = error.debugDescription // Crashes here

    return log
}

Note:

  • error.description also seems to crash
  • error.localizedDescription doesn't crash but doesn't have meaningful description of the actual error. It has a very generic error saying operation couldn't be completed.

Some background info:
In my app there are some errors that could be ignored, so I was trying to indent errors that could be ignored and encapsulate hard errors with "***"

Questions:

  1. Am I missing something or is this a bug ?
  2. Is there a better way to log with different levels of errors so that it can be differentiated visually on the console ?

What does print(error) or print(error.localizedDescription) show?

print(error) - crashes the app

print(error.localizedDescription) prints The operation couldn’t be completed. (Cocoa error 1570.)

The core data error is occurred because of validation failure of a non-nil field.

Not sure why printing the error causes
EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

I have made a mockup of how I am handling my error, not sure if it is the correct approach.

I just feel the error for some reason gets released. Any help on this would be much appreciated.

Note: The mockup code doesn't crash, but the real code crashes when there is a core data field validation error that is thrown.

import CoreData

func mockCoreDataFunction() throws {
    
    //This is just a mock up
    let error = NSError(domain: "aaa", code: 1, userInfo: nil)
    
    throw error
}

func f1() throws {
    
    let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    
    var someError : Error?
    
    context.performAndWait {
        
        do {
            
            try mockCoreDataFunction()
        }
        catch {
            someError = error
        }
    }
    
    if let errorToThrow = someError {
        throw errorToThrow
    }
}

do {
    for _ in 1...3 {
        try f1()
    }
}
catch {
    print(error)
}

I cannot reproduce the problem. I ran your code in a Xcode 9.4 command line app, and it just printed

 Error Domain=aaa Code=1 "(null)"

as one would expect, without crashing.

Yes, you are correct, that code doesn't cause a crash.

I have a similar code which produces a core data error which causes the actual crash. The underlying error was caused when a core data entity non-nil field was saved with a nil value . It was a validation failure (constraint violation)

When I was trying to print the debug description of the error that's when it crashed.

Since it involves core data ... I was finding it difficult to express the code (as it involves entity and xcdatamodel etc).

I wanted to know if the pattern I was following was correct. The code shown is mocked up code to express the pattern I am following in my code.

Exception:
Thread 10: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

My Guess: (I could be wrong):
I am just guessing it gets released and debug description causes a crash.