-[NSManagedObjectContext save:] fails but gives no NSError

  • The following code snippet -saves an NSManagedObjectContext and logs
    debugging info:

    NSLog(@"11499 moc %x has %d insertedObjects",
        [self managedObjectContext],
        [[[self managedObjectContext] insertedObjects] count]) ;
    NSLog(@"11876 Before saving, &error = %x", &error) ;
    BOOL savedOK = [[self managedObjectContext] save:&error] ;
    NSLog(@"11935 savedOK = %d", savedOK) ;
    NSLog(@"12500 NSError saving = %@", error) ;

    Gives me this:

    11499 moc 15a630e0 has 1281 insertedObjects
    11876 Before saving, &error = bfffef9c
    11935 savedOK = 0
    12500 NSError saving = (null)

    Examining the store's xml file shows that indeed the save operation
    failed.  Its file modification time is 24 hours ago.  But, darn, the
    moc didn't set any NSError.

    The problem is apparently some corruption in that xml file, because if
    I delete that file and re-run, everything works fine.  However, other
    than a few force-quits, I have not done anything in the last 24 hours
    which should have corrupted the file.  I have not made any changes to
    the data model or schema.

    I can't see anything wrong in the apparently-corrupt file.  Comparing
    it file with the newly-created one that works, the <metadata> is the
    same and the <databaseInfo> is the same except for different <UUID>
    and <nextObjectID>, but these differences seem to be expected.

    Anyone know what the unreported error might be?  I now believe that
    this also happened about a week ago, and I'm worried that some user
    operation might corrupt the file as I apparently did.

    Jerry Krinock
  • After I discovered and removed a bunch of stupid code, this problem
    went away.  It appears that I was either trying to insert or delete
    objects twice, or trying to insert objects with relationships to
    objects that had been deleted (inconsistent object graph).

    Lesson: Do not assume that -[NSManagedObjectContext save:] will set
    its argument to an NSError* whenever an error occurs.  Always check
    its return BOOL value, because more commonly when it fails it returns
    NO but does ^not^ set the NSError*.
  • On Nov 23, 2007, at 9:24 AM, Jerry Krinock wrote:
    > After I discovered and removed a bunch of stupid code, this problem
    > went away.  It appears that I was either trying to insert or delete
    > objects twice, or trying to insert objects with relationships to
    > objects that had been deleted (inconsistent object graph).
    > Lesson: Do not assume that -[NSManagedObjectContext save:] will set
    > its argument to an NSError* whenever an error occurs.  Always check
    > its return BOOL value, because more commonly when it fails it
    > returns NO but does ^not^ set the NSError*.
    >
    Under what circumstances is it not setting an error?

    mmalc
  • On 2007 Nov, 23, at 14:46, mmalc crawford wrote:

    > Under what circumstances is it not setting an error?

    Unfortunately, I can't say for sure, because when it wouldn't tell me
    what the error was, I took a broad look at what the hell I was doing
    and realized that my code and data model were maintaining an
    unnecessary entity.  It looked like, prior to the -save:, I could have
    been either (a) inserting or deleting the same objects twice, or (b)
    inserting objects with relationships to objects that had been
    deleted.  (Multiple objects had relationships to the same other
    objects, with Delete Rule = 'Cascade'.  Oops.)  But once I realized
    that these other objects were not necessary, I got rid of their entity
    and all that code, and things have been saving happily ever since.

    What I am sure about is that, as per the code in my original post,
    although I was giving -save: an NSError**, it was returning NO, my
    store file on the disk was not touched, and the NSError* was nil.

    If it ever happens again, I'll test more closely and let you know.
  • On Nov 23, 2007, at 9:47 PM, Jerry Krinock wrote:

    > What I am sure about is that, as per the code in my original post,
    > although I was giving -save: an NSError**, it was returning NO, my
    > store file on the disk was not touched, and the NSError* was nil.
    >
    > If it ever happens again, I'll test more closely and let you know.

    Is there any chance you can do a diff between what you have in your
    SCM system and what you have now, that works, and file a bug
    describing what you were doing previously?

    You should *never* rely on an output NSError argument being set to a
    non-nil as a sign of an error; you should *always* check the actual
    result of the method or function, and only look at the returned
    NSError after that.  However, it's still a serious bug for any API
    that takes an output NSError parameter to fail without returning a
    corresponding NSError, and it would be worth pursuing.

    Thanks!

      -- Chris
  • On 2007 Nov, 23, at 22:38, Chris Hanson wrote:

    > Is there any chance you can do a diff between what you have in your
    > SCM system and what you have now, that works, and file a bug
    > describing what you were doing previously?

    Well, chief, fortunately I didn't have to do that.

    The problem was that I had implemented  validateForInsert:
    (NSError**)error.  I was returning NO, but ^I^ was not setting that
    NSError.  When I did, I then got it back in save:, as expected.

    Apparently, if -validateForInsert: returns NO, save: simply passes on
    whatever error it gets, or doesn't get.  Not ideal behavior, but not a
    bug.  Something like, "You didn't give me an error in -
    validateForInsert:, Stupid" would be better.

    Thanks,

    Jerry
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today