{"record":{"id":"21aa61721d48d22a","repo":"opendataloader-project/opendataloader-pdf","slug":"invalid-upload-response-missing-data-field","errorCode":null,"errorMessage":"Invalid upload response: missing data field","messagePattern":"Invalid upload response: missing data field","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java","lineNumber":205,"sourceCode":"            .build();\n\n        try (Response response = httpClient.newCall(request).execute()) {\n            if (!response.isSuccessful()) {\n                ResponseBody body = response.body();\n                String bodyStr = body != null ? body.string() : \"\";\n                throw new IOException(\"Hancom upload failed with status \" + response.code() + \": \" + bodyStr);\n            }\n\n            ResponseBody body = response.body();\n            if (body == null) {\n                throw new IOException(\"Empty response body from upload\");\n            }\n\n            JsonNode root = objectMapper.readTree(body.string());\n            // Response format: {\"codeNum\":0,\"code\":\"file.upload.success\",\"data\":{\"fileId\":\"...\",...}}\n            JsonNode dataNode = root.get(\"data\");\n            if (dataNode == null) {\n                throw new IOException(\"Invalid upload response: missing data field\");\n            }\n            JsonNode fileIdNode = dataNode.get(\"fileId\");\n            if (fileIdNode == null || !fileIdNode.isTextual()) {\n                throw new IOException(\"Invalid upload response: missing fileId in data\");\n            }\n\n            return fileIdNode.asText();\n        }\n    }\n\n    /**\n     * Retrieves visual info for an uploaded file.\n     *\n     * @param fileId The file ID from upload.\n     * @return The visual info JSON response.\n     * @throws IOException If the request fails.\n     */\n    private JsonNode getVisualInfo(String fileId) throws IOException {","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log the full root.toString() to see the actual response JSON structure and identify what fields the server is returning.","Check the 'codeNum' and 'code' fields in the response — a non-zero codeNum typically indicates a business-logic failure with a descriptive code.","Verify the client library version matches the Hancom API version you are connecting to.","If using a custom or mock server, ensure the response follows the expected {\"data\":{\"fileId\":...}} schema.","Contact Hancom support with the full response JSON if the server's contract appears to have changed."],"exampleFix":"// before: throws on missing 'data' field with no diagnostics\nJsonNode dataNode = root.get(\"data\");\nif (dataNode == null) {\n    throw new IOException(\"Invalid upload response: missing data field\");\n}\n\n// after: log the full response for diagnosis\nJsonNode dataNode = root.get(\"data\");\nif (dataNode == null) {\n    throw new IOException(\"Invalid upload response: missing data field. \"\n        + \"Full response: \" + root);\n}","handlingStrategy":"validation","validationCode":"// Cannot pre-validate the server's response schema from the client side.\n// To diagnose, add a response logging interceptor:\nOkHttpClient client = new OkHttpClient.Builder()\n    .addInterceptor(chain -> {\n        Response resp = chain.proceed(chain.request());\n        LOGGER.info(\"Upload response: \" + resp.peekBody(Long.MAX_VALUE).string());\n        return resp;\n    })\n    .build();","typeGuard":null,"tryCatchPattern":"try {\n    fileId = client.uploadFile(pdfBytes);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"missing data field\")) {\n        // API contract mismatch — log and escalate, do not retry blindly\n        LOGGER.severe(\"Upload response schema mismatch. Server may be a different API version.\");\n        throw e;\n    }\n    throw e;\n}","preventionTips":["Pin the client library version to match the Hancom API version you are deploying against.","Add an OkHttp response logging interceptor during development to verify response schemas.","When using mock servers for testing, replicate the exact response structure the real server returns.","Log the full JSON response on schema validation failures for diagnosis."],"tags":["hancom","json-parsing","upload","hybrid","api-contract"],"backgroundTag":null,"analyzedSha":"a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8","analyzedAt":"2026-08-14T05:22:03.953Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}