opendataloader-project/opendataloader-pdf · error · IOException

Invalid upload response: missing data field

Error message

Invalid upload response: missing data field

What it means

The upload response JSON was successfully parsed by Jackson but does not contain the expected 'data' top-level field. The expected response format is {"codeNum":0,"code":"file.upload.success","data":{"fileId":"...",...}}. The absence of 'data' means the server returned a structurally different response — possibly an error envelope that still returned HTTP 200, or an API version mismatch where the field was renamed.

Source

Thrown at java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java:205

            .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");
            }

            return fileIdNode.asText();
        }
    }

    /**
     * Retrieves visual info for an uploaded file.
     *
     * @param fileId The file ID from upload.
     * @return The visual info JSON response.
     * @throws IOException If the request fails.
     */
    private JsonNode getVisualInfo(String fileId) throws IOException {

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Log the full root.toString() to see the actual response JSON structure and identify what fields the server is returning.
  2. Check the 'codeNum' and 'code' fields in the response — a non-zero codeNum typically indicates a business-logic failure with a descriptive code.
  3. Verify the client library version matches the Hancom API version you are connecting to.
  4. If using a custom or mock server, ensure the response follows the expected {"data":{"fileId":...}} schema.
  5. Contact Hancom support with the full response JSON if the server's contract appears to have changed.

Example fix

// before: throws on missing 'data' field with no diagnostics
JsonNode dataNode = root.get("data");
if (dataNode == null) {
    throw new IOException("Invalid upload response: missing data field");
}

// after: log the full response for diagnosis
JsonNode dataNode = root.get("data");
if (dataNode == null) {
    throw new IOException("Invalid upload response: missing data field. "
        + "Full response: " + root);
}
Defensive patterns

Strategy: validation

Validate before calling

// Cannot pre-validate the server's response schema from the client side.
// To diagnose, add a response logging interceptor:
OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(chain -> {
        Response resp = chain.proceed(chain.request());
        LOGGER.info("Upload response: " + resp.peekBody(Long.MAX_VALUE).string());
        return resp;
    })
    .build();

Try / catch

try {
    fileId = client.uploadFile(pdfBytes);
} catch (IOException e) {
    if (e.getMessage().contains("missing data field")) {
        // API contract mismatch — log and escalate, do not retry blindly
        LOGGER.severe("Upload response schema mismatch. Server may be a different API version.");
        throw e;
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling HancomClient.uploadFile(pdfBytes) when the server returns valid JSON with a 2xx status but the root object has no 'data' key. This happens when: the server returns a business-logic error inside a 200 response (e.g., {"codeNum":1,"code":"file.upload.failed","message":"..."} with no data), or the API version changed and the response schema was restructured.

Common situations: API version mismatch between the client library and the server (field renamed from 'data' to 'result' or 'payload'); server returns a logical error (file too large, unsupported PDF version) wrapped in a 200 with a non-standard JSON envelope; mock/stub server used during testing returns a simplified response missing the 'data' wrapper.

Related errors


AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14). Data as JSON: /api/errors/21aa61721d48d22a. Report an issue: GitHub.