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

  1. Read the HTTP status/body in the message for the specific Salesforce cause
  2. Re-authenticate and re-run the job if the token expired (401)
  3. Wait and retry respecting Retry-After if status 429 (rate limit)
  4. 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

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/b8acdd0467f5bc02. Report an issue: GitHub.