CoreData+MagicalRecord NSInternalConsistencyException "Statement is still active" crash

Viewed 442

Ok, so I have an app that is running a fairly standard CoreData + MagicalRecord stack. It's got one of these:

MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreAtURL(whisperStoreURL)

To perform operations on our CoreData model we do two different things.

  1. MagicalRecord.saveWithBlock/MagicalRecord.saveWithBlockAndWait calls from the main or any other thread
  2. An NSOperationQueue full of NSOperations that contain a single MagicalRecord.saveWithBlockAndWait call.

This all works pretty well, except for a large crash in production, stack trace below. It seems to occur as if I was violating the CoreData multithreading rules, except as far as I can tell, I'm not. Objects/Contexts are never passed between threads.

When CoreData concurrency debugging is turned on, on our local machines we sometimes get a multithreading violation (AllThatIsLeftToUsIsHonor) but it doesn't point to anything in particular as the cause. This may be related, or it may not.

I also tried plugging in https://github.com/GrahamDennis/GDCoreDataConcurrencyDebugging to see if it provided any more useful information about concurrency violations. It throws out a lot of errors about release being called on a different queue from the one the object was created on, but apparently this is a false positive.

I'm not even really sure what "statement is still active" means. Googling around it seems like it has something to do with multithreading problems, but I'm 99% sure we aren't breaking any of the rules.

I'm pretty sure having multiple MagicalRecord blocks doing stuff at the same time shouldn't be an issue. In my app, one NSOperation might be saving some stuff, while another block on some other thread is also saving some stuff, while the main thread itself might be writing to the default context and saving that using MR_saveToPersistentStoreAndWait.

I should mention that due to legacy code that was ported over to MagicalRecord recently, there are many calls to MR_saveToPersistentStoreAndWait on the main thread for some stuff that hasn't been moved to background threads yet. This has worked fine until a recent release upped the amount of MagicalRecord/CoreData stuff in the codebase significantly.

I'm running out of things to investigate other than pushing vague attempts to fix the problem to production. Any advice on how to properly diagnose where the multi-threading problem is would be appreciated.

The stack for the crash (in a background thread) looks like this:

Fatal Exception: NSInternalInconsistencyException
statement is still active

Thread : Fatal Exception: NSInternalInconsistencyException
0  CoreFoundation                 0x1844d1900 __exceptionPreprocess
1  libobjc.A.dylib                0x183b3ff80 objc_exception_throw
2  CoreData                       0x185f32fbc -[NSSQLiteStatement cachedSQLiteStatement]
3  CoreData                       0x185f327e4 -[NSSQLiteConnection prepareSQLStatement:]
4  CoreData                       0x185f43020 -[NSSQLChannel selectRowsWithStatement:]
5  CoreData                       0x18604534c newFetchedRowsForFetchPlan_MT
6  CoreData                       0x185f3a7e4 -[NSSQLCore objectsForFetchRequest:inContext:]
7  CoreData                       0x185f3a218 -[NSSQLCore executeRequest:withContext:error:]
8  CoreData                       0x186001910 __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke
9  CoreData                       0x186009d58 gutsOfBlockToNSPersistentStoreCoordinatorPerform
10 CoreData                       0x185ffc5c8 _perform
11 CoreData                       0x185f39e70 -[NSPersistentStoreCoordinator executeRequest:withContext:error:]
12 CoreData                       0x185f38938 -[NSManagedObjectContext executeFetchRequest:error:]
13 CoreData                       0x185fda318 -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
14 CoreData                       0x185fdaa44 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke
15 CoreData                       0x185fcc76c _perform
16 CoreData                       0x185fda824 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
17 CoreData                       0x185f38938 -[NSManagedObjectContext executeFetchRequest:error:]
18 whisper                        0x1003bd5bc __67+[NSManagedObject(MagicalRecord) MR_executeFetchRequest:inContext:]_block_invoke (NSManagedObject+MagicalRecord.m:54)
19 CoreData                       0x185fd1080 developerSubmittedBlockToNSManagedObjectContextPerform
20 CoreData                       0x185fd0f48 -[NSManagedObjectContext performBlockAndWait:]
21 whisper                        0x1003bd500 +[NSManagedObject(MagicalRecord) MR_executeFetchRequest:inContext:] (NSManagedObject+MagicalRecord.m:50)
22 whisper                        0x1003bd794 +[NSManagedObject(MagicalRecord) MR_executeFetchRequestAndReturnFirstObject:inContext:] (NSManagedObject+MagicalRecord.m:77)
23 whisper                        0x1003bba84 +[NSManagedObject(MagicalFinders) MR_findFirstByAttribute:withValue:inContext:] (NSManagedObject+MagicalFinders.m:107)
24 whisper                        0x1003bbdfc +[NSManagedObject(MagicalFinders) MR_findFirstOrCreateByAttribute:withValue:inContext:] (NSManagedObject+MagicalFinders.m:150)
25 whisper                        0x10023325c specialized FetchWhispersForFeedResponseProcessor.processWhispers([String : AnyObject]) -> () (FetchWhispersForFeedResponseProcessor.swift:107)
26 whisper                        0x100232250 FetchWhispersForFeedResponseProcessor.processStatusCode200() -> () (FetchWhispersForFeedResponseProcessor.swift:76)
27 whisper                        0x10023199c FetchWhispersForFeedResponseProcessor.processWithLocalContext(NSManagedObjectContext) -> () (FetchWhispersForFeedResponseProcessor.swift:22)
28 whisper                        0x100222d20 CoreDataResponseProcessor.(main(CoreDataResponseProcessor) -> () -> ()).(closure #1) (CoreDataResponseProcessor.swift:15)
29 whisper                        0x1003b6144 __47+[MagicalRecord(Actions) saveWithBlockAndWait:]_block_invoke (MagicalRecord+Actions.m:48)
30 CoreData                       0x185fd1080 developerSubmittedBlockToNSManagedObjectContextPerform
31 libdispatch.dylib              0x183f255f0 _dispatch_client_callout
32 libdispatch.dylib              0x183f3089c _dispatch_barrier_sync_f_invoke
33 CoreData                       0x185fd0f68 -[NSManagedObjectContext performBlockAndWait:]
34 whisper                        0x1003b60ac +[MagicalRecord(Actions) saveWithBlockAndWait:] (MagicalRecord+Actions.m:44)
35 whisper                        0x100222a58 CoreDataResponseProcessor.main() -> () (CoreDataResponseProcessor.swift:16)
36 whisper                        0x100222b9c @objc CoreDataResponseProcessor.main() -> () (CoreDataResponseProcessor.swift)
37 Foundation                     0x184dbb348 -[__NSOperationInternal _start:]
38 Foundation                     0x184e7a728 __NSOQSchedule_f
39 libdispatch.dylib              0x183f255f0 _dispatch_client_callout
40 libdispatch.dylib              0x183f31634 _dispatch_queue_drain
41 libdispatch.dylib              0x183f290f4 _dispatch_queue_invoke
42 libdispatch.dylib              0x183f33504 _dispatch_root_queue_drain
43 libdispatch.dylib              0x183f33224 _dispatch_worker_thread3
44 libsystem_pthread.dylib        0x184139470 _pthread_wqthread
45 libsystem_pthread.dylib        0x184139020 start_wqthread
0 Answers
Related