[SalesForce] Unable to upload large files (not above 4MB) as attachment with apex class method from LWC. How to overcome this issue

LWC method to convert selected file content to base64 String and call the apex method for uploading as related Notes and Attachment on a particular record

myComponent.js

const toBase64 = file => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
});

async handleDeviceFileSelection(event) {
    const file = event.target.files[0];
    const fileName = file.name;
    const base64String = await toBase64(file);
    const encodedString = base64String.split('base64,')[1];

    saveAttachment({parentId: parentId, file: encodedString, name: fileName}).then(() => {
       // do something based on the response
    }).catch((err) => {
       showError(this, err)
    })
}

Apex Controller

@AuraEnabled
    public static void saveAttachment(String parentId, String file, String name){
        Attachment attachment = new Attachment();
        attachment.Body = EncodingUtil.base64Decode(file);
        attachment.Name = String.valueOf(name);
        attachment.ParentId = parentId;

        if (Schema.sObjectType.Attachment.isCreateable()) {
            insert attachment;
        }
    }

Note: I can't use lightning-file-upload as I have to handle few things before upload and also mine is lightning out app, so anyway lightning-file-upload is not compatible with the application. Also I guess upload with Connection.js and Jsforce does not with lightning web components!!.

This throws heap size limit error in apex even for file of 5MB. Sometimes it throw
"[AuraClientInputException from server] Unexpected request input. Expected input format: "Max message parameter length is 4194304 characters."."

Thanks in Advance for any help with this issue

Best Answer

It's pretty difficult (read: basically impossible) to work around the heap limit in Apex here.

No matter what approach you try to take, you'll always run into the issue of needing to have the data in-memory (i.e. on the heap) to be able to save the data. On other platforms (I'm thinking along the lines of Apache + PHP) you'd be able to utilize less memory (at the cost of needing to make more requests) by chunking your data and then reassembling it on the server. I don't think there's much benefit to that approach on the Salesforce platform though.

Your best bet here is probably to use the REST API that Salesforce provides. There is documentation specifically for inserting/updating blob data

In a nutshell, instead of calling an Apex method, you'll make an http call from your component to an endpoint like https://yourInstance.salesforce.com/services/data/v23.0/sobjects/Document/ (and set various headers, set the boundary string, and include your target data in the request too. The documentation goes into more depth).

Related Topic