Basically I'm trying to write an after insert trigger for ContentVersion the object. Whenever a new record is created by user ID "0052o000008YA5WAAW", I want to then check ContentDocumentLink and see if the ContentDocumentId exists in ContentDocumentLink and if the LinkedEntityID starts with 'a3r' which is a custom object of mine. Then taking that LinkedEntityID for example "a3r7T000000L4K7QAK". That value could exist in a field called Ironclad_Information__c on the objects Account, Opportunity, or Quote.

Then create a new ContentDocumentLink with following parameters

Visiblity = 'All Users'
LinkedEntityId = Account, Opportunity, or Quote (However many object records you found matching "a3r7T000000L4K7QAK" in the field Ironclad_Information__c across the three objects in this example) 
ContentDocumentLink = the Trigger.new value of the ContentDocumentId present in ContentVersion

In my example I was just focusing on Quote, but ideally I would like to create for all objects.

So I corrected my illegal set assignment, by stringifying my Set to an ID. But now I get

17:43:07:006 FATAL_ERROR System.QueryException: Implementation restriction: ContentDocumentLink requires a filter by a single Id on ContentDocumentId or LinkedEntityId using the equals operator or multiple Id's using the IN operator.

And I can't see why, I am doing an In statement in my SOQL

for (ContentDocumentLink cvlink: [
    SELECT Id, ContentDocumentId, LinkedEntityId 
    FROM ContentDocumentLink 
    WHERE ContentDocumentId IN:contentDocumentIdSet

The contentDocumentIdSet was set by my Trigger firing and iterating them into a set. Why is it erroring on that?

trigger AutoCreateContentDocumentLinkQuote on ContentVersion (after insert) {
    Set<Id> contentDocumentIdSet = new Set<Id>();
    for(ContentVersion cv:trigger.new)
        if(cv.ContentDocumentId != null && cv.CreatedById == '0052o000008YA5WAAW')
    Set<Id> CleanedDocList = new Set<Id>();
    //Checks if Record was Made by Legal
    for(ContentDocumentLink cvlink: [SELECT Id, ContentDocumentId, LinkedEntityId FROM ContentDocumentLink WHERE ContentDocumentId IN:contentDocumentIdSet])
    {   String idtext = String.valueof(cvlink.Id);
        if(idtext.left(3) == 'a3r')
    //Find Quote that Exists
    List<Quote> q1 = [Select Id from Quote where Ironclad_Information__c in: contentDocumentIdSet limit 1];
    //Insert ContentDocumentLink
    ContentDocumentLink cDocLink = new ContentDocumentLink();
    cDocLink.ContentDocumentId = String.valueof(CleanedDocList);
    cDocLink.LinkedEntityId = q1[0].Id;//Add Quote ID
    cDocLink.ShareType = 'V';  //V - Viewer permission. C - Collaborator permission. I - Inferred permission.
    cDocLink.Visibility = 'InternalUsers';//AllUsers, InternalUsers, SharedUsers
    Insert cDocLink;

1 Answer 1


If the set is empty, this will cause the exception you see here. Abort early if there are no Id values:

if(contentDocumentIdSet.isEmpty()) {

Also, this code won't work:

String idtext = String.valueof(cvlink.Id);
if(idtext.left(3) == 'a3r')

You're checking the Id field, so the type will always be a ContentDocumentLink Id, not anything else. By the way, you should avoid the key prefix check model. Do this instead:

if(cvlink.LinkedEntityId.getSObjectType() == MyCustomObject__c.sObjectType) {

It's a bit longer but provides compile-time safety. Also, key prefixes are case sensitive, but the == operator in Apex is case-insensitive, so you could end up matching a3r and a3R, which may be two different, legal prefixes in your org.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .