{"record":{"id":"b8acdd0467f5bc02","repo":"apache/seatunnel","slug":"bulk-results-failed","errorCode":"BULK_RESULTS_FAILED","errorMessage":"HTTP \" + status + \": \" + body","messagePattern":"HTTP \" \\+ status \\+ \": \" \\+ body","errorType":"error_code","errorClass":"SalesforceConnectorException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-salesforce/src/main/java/org/apache/seatunnel/connectors/seatunnel/salesforce/client/SalesforceClient.java","lineNumber":298,"sourceCode":"     * buffering happens at this layer, only one page's CSV body is held at a time.\n     */\n    private void downloadResults(String jobId, int columnCount, Consumer<Object[]> rowConsumer) {\n        String url =\n                authorizedInstanceUrl\n                        + String.format(JOB_RESULTS_PATH, params.getApiVersion(), jobId);\n        String locator = null;\n\n        do {\n            String requestUrl = locator == null ? url : url + \"?locator=\" + locator;\n            HttpGet get = new HttpGet(requestUrl);\n            get.setHeader(HttpHeaders.AUTHORIZATION, \"Bearer \" + accessToken);\n            get.setHeader(HttpHeaders.ACCEPT, \"text/csv\");\n\n            try (CloseableHttpResponse response = httpClient.execute(get)) {\n                int status = response.getStatusLine().getStatusCode();\n                String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);\n                if (status != 200) {\n                    throw new SalesforceConnectorException(\n                            SalesforceConnectorErrorCode.BULK_RESULTS_FAILED,\n                            \"HTTP \" + status + \": \" + body);\n                }\n                Header locatorHeader = response.getFirstHeader(\"Sforce-Locator\");\n                locator =\n                        (locatorHeader != null && !\"null\".equals(locatorHeader.getValue()))\n                                ? locatorHeader.getValue()\n                                : null;\n                parseCsvInto(body, columnCount, rowConsumer);\n            } catch (SalesforceConnectorException e) {\n                throw e;\n            } catch (Exception e) {\n                throw new SalesforceConnectorException(\n                        SalesforceConnectorErrorCode.BULK_RESULTS_FAILED, e);\n            }\n        } while (locator != null);\n    }\n","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-salesforce/src/main/java/org/apache/seatunnel/connectors/seatunnel/salesforce/client/SalesforceClient.java#L280-L316","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// ensure fresh token and valid job before download\n// GET /jobs/query/{jobId} expect state == \"JobComplete\" before fetching results","typeGuard":null,"tryCatchPattern":"for (int attempt = 0; attempt < 3; attempt++) {\n    try {\n        client.downloadResults(jobId, ...);\n        break;\n    } catch (SalesforceConnectorException e) {\n        if (e.getMessage().contains(\"HTTP 429\") || e.getMessage().contains(\"HTTP 401\")) {\n            sleep(backoff(attempt));\n        } else {\n            throw e;\n        }\n    }\n}","preventionTips":["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"],"tags":["http","salesforce","bulk-api"],"backgroundTag":"http-error-response","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}