With the Summer ’10 release, we have added the ability to retrieve the original data that you send in a Bulk API batch. We keep this data around for 7 days just as we keep the job info, batch info and batch result files.

Because you can now directly retrieve the original data, it has become easier to do things like building a CSV file of all records with errors. You can do this without keeping track of the mappings between the original data set and the batches you submitted to the job.

Here is a very simple Java sample showing how you can do this:  

import java.io.File;
import java.io.FileWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import com.sforce.async.CSVReader;
import com.sforce.async.BatchInfo;
import com.sforce.async.RestConnection;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectorConfig;
public class GetErrors {
* @param args
public static void main(String[] args) {
try {
String username = args[0];
String password = args[1];
String jobId = args[2];
ConnectorConfig config = new ConnectorConfig();
// Instantiating a new partner connection will perform
// API login and set the session ID in the ConnectorConfig.
// We don't actually need the PartnerConnection itself.
PartnerConnection p = new PartnerConnection(config);
// Build REST API endpoint from Partner endpoint
String restEndpoint = config.getServiceEndpoint().substring(0, config.getServiceEndpoint().indexOf("Soap"))
+ "async/19";
RestConnection rc = new RestConnection(config);
FileWriter out = new FileWriter(new File("errors.csv"));
boolean headerWritten = false;
for (BatchInfo b : rc.getBatchInfoList(jobId).getBatchInfo()) {
if (b.getState().equals(BatchStateEnum.Completed) && b.getNumberRecordsFailed() > 0) {
URL resultURL = new URL(restEndpoint + "/job/" + jobId + "/batch/" + b.getId() + "/result");
URL requestURL = new URL(restEndpoint + "/job/" + jobId + "/batch/" + b.getId() + "/request");
HttpURLConnection resultC = (HttpURLConnection) resultURL.openConnection();
HttpURLConnection requestC = (HttpURLConnection) requestURL.openConnection();
resultC.addRequestProperty("X-SFDC-Session", config.getSessionId());
requestC.addRequestProperty("X-SFDC-Session", config.getSessionId());
CSVReader resultR = new CSVReader(resultC.getInputStream());
CSVReader requestR = new CSVReader(requestC.getInputStream());
ArrayList resultHeader = resultR.nextRecord();
ArrayList requestHeader = requestR.nextRecord();
while (true) {
ArrayList resultRow = resultR.nextRecord();
ArrayList requestRow = requestR.nextRecord();
if (resultRow == null) {
if (requestRow != null) {
System.out.println("Result list finish before request list in batch " + b.getId());
if (resultRow.get(1).equals("false")) {
if (!headerWritten) {
// We don't write out the header until we have at least one error record
for (String name : requestHeader) {
out.write(""" + name.replace(""", """") + "",");
headerWritten = true;
for (String field : requestRow) {
if (field == null) {
} else {
out.write(""" + field.replace(""", """") + "",");
if (resultRow.get(3) != null) {
out.write(""" + resultRow.get(3).replace(""", """") + ""n");
} else {
out.write("NO ERROR MESSAGEn");
} catch (Exception e) {
// TODO Auto-generated catch block

You’ll need wsc-19 and a v19 partner jar to run it. Currently the WSC site doesn’t have the partner jar, but you can compile it yourself using WSC and a downloaded partner WSDL file from your org.

  1. Download a partner WSDL file by logging into your org and go to Setup -> Develop -> API -> Partner WSDL.
  2. Run something like: java -cp wsc-19.jar com.sforce.ws.tools.wsdlc `pwd`/partner.wsdl `pwd`/partner-19.jar
  3. Compile the class above and execute it with: java -cp wsc-19.jar:partner-19.jar GetErrors [sfdc_username] [sfdc_password] [jobId]
  4. The errors will be downloaded into errors.csv. The last column in the file will contain the error message for each row.

Disclaimer: I hacked this together pretty quickly and I haven’t done much testing. This is just meant as an example. If you put this into use, make sure you review and test your code thoroughly.

Also, note that the records will not be ordered the same way as in your original data set.

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS