20

Are there any work arounds for this issue?

I'm trying to upload a file(attachment) to an 3rd party REST API Service. It works fine until my file sizes get about ~5 mb. Then I start getting the following error:

common.apex.runtime.impl.ExecutionException: String length exceeds maximum: 6000000

The code that I'm using is a little hacky due to the requirements of the external service (must be multipart, does not accept base64).

Pretty much it takes the contents of the attachment blob, and combines them with the multipart header then puts them back into a blob.

Here's the code I'm using. There are some statics that I left out but you get the point.

public static void UploadAttachment(Attachment attachment, String folder){

    String boundary = '----------------------------741e90d31eff';
    String header = '--'+boundary+'\nContent-Disposition: form-data; name="file"; filename="'+attachment.name+'";\nContent-Type: application/octet-stream';
    String footer = '\r\n--'+boundary+'--';              
    String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
    while(headerEncoded.endsWith('=')){
        header+=' ';
        headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
    }
    String bodyEncoded = EncodingUtil.base64Encode(attachment.body);
    String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));

    Blob bodyBlob = null;
    String last4Bytes = bodyEncoded.subString(bodyEncoded.length()-4,bodyEncoded.length());
    if(last4Bytes.endsWith('=')){
        Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
        HttpRequest tmp = new HttpRequest();
        tmp.setBodyAsBlob(decoded4Bytes);
        String last4BytesFooter = tmp.getBody()+footer;   
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded.subString(0,bodyEncoded.length()-4)+EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
    }
    else{
        bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
    }

    HttpRequest req = new HttpRequest();
    req.setHeader('Authorization', authorizationData);
    req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
    req.setMethod('POST');
    req.setEndpoint(server+storageService+'/'+folder);
    req.setBodyAsBlob(bodyBlob);
    req.setTimeout(120000);

    Http http = new Http();
    HTTPResponse res = http.send(req);
}

Code modified from this blog post

7
  • 3
    Is this an future method? If not, I think this limit is there as a quick way to avoid going over the heap size of 6MB. It's 12mb in future and batch contexts. Commented Mar 1, 2014 at 1:49
  • Agreed. Check salesforce.com/us/developer/docs/apexcode/Content/… for more limit information. I don't know why you didn't hit the 3MB limit on HTTP requests - ("Maximum size of callout request or response (HTTP request or Web services call)" from the URL I referenced - so that's pretty interesting. Commented Mar 1, 2014 at 17:21
  • Perhaps the 6M string length limit already corresponds to the 12Mbyte heap limit as AFAIK an Apex string is a JVM string using 2 bytes per character. But as David mentions there are other limits to run foul of in any case. Apex doesn't have streaming IO classes so large data volumes are always going to be problematic.
    – Keith C
    Commented Mar 1, 2014 at 23:27
  • 1
    May be you should use third party ETL tool like Cast Iron to pull your attachment from SFDC and push it to your destination system. If you do not want to invest in ETL tool then you can write your won scrip that will pull this attachments from SFDC and push it into destination system using the API. Commented Apr 28, 2014 at 5:58
  • 1
    The simplest solution ended up being proxying it through a Node server. Just pipe the response straight back to saleforce.
    – NSjonas
    Commented Apr 29, 2014 at 19:57

1 Answer 1

10

Unfortunately you're SOL when it comes to that sort of limit, your only route is going to be moving the operation off Salesforce.

One option would be to create a Heroku app with a single endpoint that takes the attachment Id. The endpoint can then retrieve the attachment and then upload it to the 3rd party server.

2
  • 3
    crazy... that's exactly what I ended up doing ;)
    – NSjonas
    Commented Jul 17, 2014 at 20:00
  • 1
    I know this is old, but you can also use the blob coverttoHex method where base64 is not supported and stream it in a multipart too
    – Ronnie
    Commented Jun 28, 2021 at 18:56

You must log in to answer this question.

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