I have a REST endpoint that, when called by a guest user, creates a ContentVersion file. When the process happens synchronously, the ContentVersion file gets created without issue. However, when the logic is changed to use Queueable, file creation fails with the message "INVALID_STATUS, Documents in a user's private library must always be owned by that user.: [OwnerId]"
Calling this service as an authenticated Salesforce user works as expected both synchronously and queueable.
I tried using the fix listed in this article but in my case, I don't have a NetworkId field available on ContentVersion since Communities is not enabled. I also tried setting all classes to "without sharing" but that didn't help either.
I've also tried setting the FirstPublishLocationId as recommended in some other places but this caused the synchronous process to begin failing with the message "INSUFFICIENT_ACCESS_OR_READONLY, You do not have the level of access necessary to perform the operation you requested. Please contact the owner of the record or your administrator if access is necessary"
All files below are greatly simplified to illustrate the issue without any noise. Again, everything works as an authenticated Salesforce user but not as a guest user.
Basic ContentVersion creation logic
public with sharing class CVDemo {
public static Id createContentVersion(){
String filename = 'Sample';
filename += DateTime.now().formatGmt('yyyy-MM-dd\'T\'HH:mm:ss');
ContentVersion contentVersion = new ContentVersion(
Title = filename,
PathOnClient = filename + '.txt',
VersionData = Blob.valueOf('Hello World'),
Origin = 'C',
ContentLocation = 'S',
FirstPublishLocationId = UserInfo.getUserId()
);
insert contentVersion;
return contentVersion.Id;
}
}
Simple Queueable to call the logic
public with sharing class CVQueueable implements Queueable{
public void execute(QueueableContext context) {
Id cvid = CVDemo.createContentVersion();
system.debug('queueable CVID: ' + cvid);
}
}
REST service
@RestResource(urlMapping='/cvDemo')
global with sharing class CVRestService {
@HttpPost
global static void handleRequest() {
RestRequest request = RestContext.request;
RestResponse response = RestContext.response;
response.addHeader('Content-Type', 'application/json');
Map<String, Object> responseBody = new Map<String, Object>();
System.debug('exec sync');
//creating the document synchronously succeeds
Id cvid = CVDemo.createContentVersion();
System.debug('sync CVID: ' + cvid);
//but trying to enqueue the document creation fails
System.debug('enqueue');
String jobId = System.enqueueJob(new CVQueueable());
responseBody.put('jobID', jobId);
response.responseBody = Blob.valueOf(JSON.serialize(responseBody));
response.statusCode = 200;
}
}