January 14, 2012

Resolved : “Field is not writeable: Sobject__Share.RowCause” !

This post is about an issue that comes with Apex managed sharing, i.e.

System.SObjectException: Field is not writeable: Sobject__Share.RowCause

We faced this problem recently, and tried searching for this problem on force.com boards, but no solution was available, I just found few open questions like

On debugging, we found that the cause of this error was update of RowCause field on “SObject__share” record. We are not changing RowCause, but accidently coping back the same value.

So the fix is to never try to update RowCause field once created the SObject__share record. If you need to change the RowCause field in Sobject__Share record, then delete it and create new one.

Here is a minimalistic apex test case that reproduces this issue :

public static testmethod void testShareRecordUpdate() {
      // A custom standard user profile with required access on the custom object Specimen__c 
        Profile p = [SELECT Id FROM profile WHERE name='Cust Standard User'];
        // mock user for the same
        User mockUser = new User(alias = 'newUser', email='newuser@tgerm.com',
                  emailencodingkey='UTF-8', lastname='Testing', 
                  languagelocalekey='en_US', localesidkey='en_US', profileid = p.Id,
                  timezonesidkey='America/Los_Angeles', username='newuser@tgerm.com' + System.now().getTime());
        // Custom sobject with no special fields, just for sake of testing 
        Specimen__c specimen = new Specimen__c();
        
        system.runAs(mockUser) {
            insert specimen;
        }
        
        // Create an edit share
        Specimen__share readShare = new Specimen__share(
               AccessLevel = 'Edit',
               RowCause = Schema.Specimen__share.RowCause.Reason1__c,
               UserOrGroupId = Userinfo.getUserId(),
               ParentId = specimen.id
            );
        insert readShare;
        
        // One can assume some other flow, queries the same Share record and attemps the update
        Specimen__share editShare = [Select AccessLevel,RowCause from Specimen__share 
                                        where UserOrGroupId = :Userinfo.getUserId() 
                                        AND ParentId =:specimen.id 
                                        AND RowCause = :Schema.Specimen__share.RowCause.Reason1__c                         
                                        ];
        
        // Comment this line to get rid of 
        // this error : "Field is not writeable: Specimen__Share.RowCause"
        editShare.RowCause = Schema.Specimen__share.RowCause.Reason1__c;
        editShare.AccessLevel = 'Read';
        update editShare;
    }

I would say this error should be something else, as the field “RowCause” is writable on record creation but not updatable.