opendataloader-project/opendataloader-pdf · error · IOException
Hancom upload failed with status %s: %s
Error message
Hancom upload failed with status %s: %s
What it means
The Hancom file upload endpoint (POST to UPLOAD_ENDPOINT) returned an HTTP status code outside the 2xx range. The error message includes both the status code and the raw response body string for diagnostics. This is a server-side rejection of the upload — authentication failure, malformed request, rate limiting, or internal server error.
Source
Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java:193
* @throws IOException If the upload fails.
*/
private String uploadFile(byte[] pdfBytes) throws IOException {
MultipartBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", DEFAULT_FILENAME,
RequestBody.create(pdfBytes, MEDIA_TYPE_PDF))
.build();
Request request = new Request.Builder()
.url(baseUrl + UPLOAD_ENDPOINT)
.post(requestBody)
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
ResponseBody body = response.body();
String bodyStr = body != null ? body.string() : "";
throw new IOException("Hancom upload failed with status " + response.code() + ": " + bodyStr);
}
ResponseBody body = response.body();
if (body == null) {
throw new IOException("Empty response body from upload");
}
JsonNode root = objectMapper.readTree(body.string());
// Response format: {"codeNum":0,"code":"file.upload.success","data":{"fileId":"...",...}}
JsonNode dataNode = root.get("data");
if (dataNode == null) {
throw new IOException("Invalid upload response: missing data field");
}
JsonNode fileIdNode = dataNode.get("fileId");
if (fileIdNode == null || !fileIdNode.isTextual()) {
throw new IOException("Invalid upload response: missing fileId in data");
}
View on GitHub (pinned to a7789b8e77)
Solutions
- Inspect the response body in the error message — Hancom returns JSON like {"codeNum":<n>,"code":"<reason>"} with a human-readable failure code.
- For 401/403: verify your API credentials are set and current for the Hancom endpoint.
- For 413: reduce PDF size (split the document or lower scan DPI) or raise the server's upload limit.
- For 429: implement exponential backoff with retry (add a delay between upload attempts).
- For 5xx: retry after a short delay; if persistent, check the Hancom service status page or contact support.
- Run the same upload via curl to isolate whether it's a client-side or server-side issue: `curl -X POST -H 'Content-Type: multipart/form-data' -F 'file=@doc.pdf' <upload-url>`.
Example fix
// before: single attempt, no retry on transient server errors
String fileId = client.uploadFile(pdfBytes);
// after: retry on 5xx with exponential backoff
String fileId = null;
for (int attempt = 0; attempt < 3; attempt++) {
try {
fileId = client.uploadFile(pdfBytes);
break;
} catch (IOException e) {
if (!e.getMessage().contains("status 5") || attempt == 2) throw e;
Thread.sleep((1L << attempt) * 1000);
}
} Defensive patterns
Strategy: retry
Validate before calling
// Validate PDF before upload
if (pdfBytes == null || pdfBytes.length == 0) {
throw new IllegalArgumentException("Cannot upload empty PDF");
}
// Check PDF signature
if (pdfBytes.length < 5 || pdfBytes[0] != '%' || pdfBytes[1] != 'P') {
throw new IllegalArgumentException("File does not start with PDF signature");
} Try / catch
try {
fileId = client.uploadFile(pdfBytes);
} catch (IOException e) {
String msg = e.getMessage();
if (msg.contains("status 429") || msg.contains("status 5")) {
// Transient — retry with backoff
Thread.sleep(2000);
fileId = client.uploadFile(pdfBytes);
} else if (msg.contains("status 401") || msg.contains("status 403")) {
// Auth failure — do not retry, fix credentials
throw new SecurityException("Authentication failed for Hancom upload", e);
} else {
throw e;
}
} Prevention
- Implement exponential backoff for 429 and 5xx responses.
- Do not retry on 401/403 — fix credentials instead.
- Check the response body for Hancom's error code (codeNum/code) to classify the failure.
- Log the HTTP status and body for every upload failure for diagnostics.
When it happens
Trigger: Calling HancomClient.uploadFile(pdfBytes) when the server rejects the multipart upload. Specific triggers: 401/403 (missing or expired API key/auth token), 413 (PDF exceeds server's max upload size), 415 (unsupported media type — the Content-Type header is wrong), 429 (rate limit exceeded), 500/502/503 (server-side processing crash or upstream dependency failure).
Common situations: API key not configured or expired; attempting to upload an extremely large PDF that exceeds the server limit; server is under maintenance or overloaded; the PDF file is corrupt and the server's intake validation rejects it; rate limiting during batch processing of many documents.
Related errors
- Empty response body from upload
- Hancom visualinfo failed with status %s: %s
- Empty response body from visualinfo
- Hybrid server is not available at %s Please check the server
- Invalid upload response: missing data field
AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14).
Data as JSON: /api/errors/02efd28b243f6057.
Report an issue: GitHub.