Actually, for service case attachments specifically, you want to leverage the ContentVersion object with proper multipart implementation. Here’s the complete approach that addresses your attachment size limits, ContentVersion handling, and multipart upload requirements:
First, implement file chunking in your Java client:
int chunkSize = 4 * 1024 * 1024; // 4MB chunks
byte[] fileBytes = Files.readAllBytes(filePath);
int chunks = (int) Math.ceil(fileBytes.length / (double) chunkSize);
For each chunk, create a multipart request with proper headers:
String boundary = "----Boundary" + System.currentTimeMillis();
HttpPost post = new HttpPost(instanceUrl + "/services/data/v59.0/sobjects/ContentVersion");
post.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
post.setHeader("Authorization", "Bearer " + accessToken);
The critical part is the ContentVersion creation strategy. Instead of trying to upload everything at once, use a two-phase approach:
Phase 1 - Create the ContentVersion record with minimal data:
ContentVersion cv = new ContentVersion();
cv.Title = fileName;
cv.PathOnClient = fileName;
cv.FirstPublishLocationId = caseId; // Links to service case
cv.ContentLocation = 'S'; // Salesforce storage
// Don't set VersionData yet
insert cv;
Phase 2 - Upload file data in chunks using the REST API PATCH method:
for (int i = 0; i < chunks; i++) {
int start = i * chunkSize;
int end = Math.min(start + chunkSize, fileBytes.length);
byte[] chunk = Arrays.copyOfRange(fileBytes, start, end);
String rangeHeader = String.format("bytes %d-%d/%d", start, end-1, fileBytes.length);
// PATCH /services/data/v59.0/sobjects/ContentVersion/{cvId}
// Header: Content-Range: {rangeHeader}
// Body: base64 encoded chunk
}
Key points for multipart upload success:
-
Attachment Size Limits: The 5MB limit applies per request, not per file. By chunking at 4MB, you stay under the threshold with buffer for headers and encoding overhead.
-
ContentVersion Object Management: Create the ContentVersion record first without VersionData, then use its ID for subsequent chunk uploads. The FirstPublishLocationId links it directly to your service case, so it appears as an attachment immediately (though not fully uploaded until all chunks complete).
-
Multipart Upload Implementation: Use Content-Range headers for each chunk. Salesforce automatically reassembles chunks based on the range information. Critical: send chunks sequentially, not in parallel, to avoid race conditions. Include a checksum in your final chunk to verify integrity.
Error handling considerations:
- Implement retry logic for individual chunk failures (don’t restart entire upload)
- Store chunk upload state in case of connection interruption
- Verify the ContentVersion.ContentSize matches your original file size after completion
- Use ContentDocument.LatestPublishedVersionId to confirm the file is fully available
For service cases specifically, you can verify the attachment is properly linked by querying ContentDocumentLink:
SELECT ContentDocumentId, LinkedEntityId
FROM ContentDocumentLink
WHERE LinkedEntityId = :caseId
This approach handles files up to 2GB (Salesforce’s absolute limit for ContentVersion). For your diagnostic files and screenshots, this should cover all use cases. The multipart strategy also provides better progress tracking - you can update users on upload percentage as each chunk completes.