apache/seatunnel · error · SalesforceConnectorException
BULK_RESULTS_FAILED
BULK_RESULTS_FAILED
Error message
HTTP " + status + ": " + body
What it means
Thrown by SalesforceClient.downloadResults when the GET to the Bulk API v2 results endpoint (with Accept: text/csv) returns a non-200 status while fetching result CSV pages. It includes the HTTP status and response body.
Source
Thrown at seatunnel-connectors-v2/connector-salesforce/src/main/java/org/apache/seatunnel/connectors/seatunnel/salesforce/client/SalesforceClient.java:298
* buffering happens at this layer, only one page's CSV body is held at a time.
*/
private void downloadResults(String jobId, int columnCount, Consumer<Object[]> rowConsumer) {
String url =
authorizedInstanceUrl
+ String.format(JOB_RESULTS_PATH, params.getApiVersion(), jobId);
String locator = null;
do {
String requestUrl = locator == null ? url : url + "?locator=" + locator;
HttpGet get = new HttpGet(requestUrl);
get.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
get.setHeader(HttpHeaders.ACCEPT, "text/csv");
try (CloseableHttpResponse response = httpClient.execute(get)) {
int status = response.getStatusLine().getStatusCode();
String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
if (status != 200) {
throw new SalesforceConnectorException(
SalesforceConnectorErrorCode.BULK_RESULTS_FAILED,
"HTTP " + status + ": " + body);
}
Header locatorHeader = response.getFirstHeader("Sforce-Locator");
locator =
(locatorHeader != null && !"null".equals(locatorHeader.getValue()))
? locatorHeader.getValue()
: null;
parseCsvInto(body, columnCount, rowConsumer);
} catch (SalesforceConnectorException e) {
throw e;
} catch (Exception e) {
throw new SalesforceConnectorException(
SalesforceConnectorErrorCode.BULK_RESULTS_FAILED, e);
}
} while (locator != null);
}
View on GitHub (pinned to cf67b549a7)
Solutions
- Read the HTTP status/body in the message for the specific Salesforce cause
- Re-authenticate and re-run the job if the token expired (401)
- Wait and retry respecting Retry-After if status 429 (rate limit)
- If 404, the job/results are gone — re-create the bulk query job
Defensive patterns
Strategy: retry
Validate before calling
// ensure fresh token and valid job before download
// GET /jobs/query/{jobId} expect state == "JobComplete" before fetching results Try / catch
for (int attempt = 0; attempt < 3; attempt++) {
try {
client.downloadResults(jobId, ...);
break;
} catch (SalesforceConnectorException e) {
if (e.getMessage().contains("HTTP 429") || e.getMessage().contains("HTTP 401")) {
sleep(backoff(attempt));
} else {
throw e;
}
}
} Prevention
- Refresh the access token if the job takes longer than the token lifetime
- Respect Bulk API rate limits; avoid hammering the results endpoint
- Do not reuse stale jobIds across runs
- Handle Sforce-Locator pagination correctly to avoid invalid follow-up requests
When it happens
Trigger: Downloading result files after job completion when the access token has expired (401), the job id is invalid or already deleted (404), or Salesforce throttles the request (429).
Common situations: Long-running jobs whose token expired before download; retrying with a stale jobId; hitting Bulk API request rate limits; incorrect results locator handling across pages.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- BULK_JOB_CREATE_FAILED
- AUTH_FAILED
- DESCRIBE_OBJECT_FAILED
- BULK_JOB_FAILED
- Failed to fetch metadata from Gravitino for metadata: %s
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/b8acdd0467f5bc02.
Report an issue: GitHub.