{"record":{"id":"b90871328164596a","repo":"opendataloader-project/opendataloader-pdf","slug":"invalid-upload-response-missing-fileid-in-data","errorCode":null,"errorMessage":"Invalid upload response: missing fileId in data","messagePattern":"Invalid upload response: missing fileId in data","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java","lineNumber":209,"sourceCode":"                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 {\n        String url = baseUrl + String.format(VISUALINFO_ENDPOINT, fileId) +\n            \"?engine=\" + ENGINE +\n            \"&dlaMode=\" + DLA_MODE +\n            \"&ocrMode=\" + OCR_MODE;","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/opendataloader-project/opendataloader-pdf/blob/a7789b8e77dd05e2b8659eb3ea12fc458f80bfb8/java/opendataloader-pdf-core/src/main/java/org/opendataloader/pdf/hybrid/HancomClient.java#L191-L227","documentation":"The upload response JSON contains a 'data' object but it lacks a 'fileId' field, or 'fileId' exists but is not a textual JSON node (e.g., it's a number or object). The fileId is critical — it is the handle used in all subsequent API calls (getVisualInfo, deleteFile). Without it, the conversion pipeline cannot proceed.","triggerScenarios":"Calling HancomClient.uploadFile(pdfBytes) when the server's 'data' object is present but structurally incomplete — fileId might be null, missing, or returned under a different key name (e.g., 'id', 'file_id', 'uid'). Also triggered if the server returns a numeric fileId that Jackson sees as non-textual via isTextual() check.","commonSituations":"API version mismatch where 'fileId' was renamed to 'id' or 'file_id'; server-side bug where the upload succeeded but the response serializer skipped the fileId field; testing against a mock server that populates 'data' with placeholder values; partial response due to serialization timeout on the server.","solutions":["Log root.toString() or dataNode.toString() to inspect the actual field names in the data object.","If the field is named differently (e.g., 'id'), update the client to check multiple possible key names or upgrade the library to match the server version.","Verify that the server is the expected version — compare the response schema against the Hancom API documentation.","If using a mock server for testing, ensure it returns {\"data\":{\"fileId\":\"test-file-id\"}}."],"exampleFix":"// before: only checks 'fileId', strict textual check\nJsonNode fileIdNode = dataNode.get(\"fileId\");\nif (fileIdNode == null || !fileIdNode.isTextual()) {\n    throw new IOException(\"Invalid upload response: missing fileId in data\");\n}\n\n// after: also log the data object for diagnosis\nJsonNode fileIdNode = dataNode.get(\"fileId\");\nif (fileIdNode == null || !fileIdNode.isTextual()) {\n    throw new IOException(\"Invalid upload response: missing fileId in data. \"\n        + \"Data object: \" + dataNode);\n}","handlingStrategy":"validation","validationCode":"// Cannot pre-validate from the client side.\n// During development, test against the real server and log the data object:\n// This is a server-side contract issue, not a client-side validation opportunity.","typeGuard":null,"tryCatchPattern":"try {\n    fileId = client.uploadFile(pdfBytes);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"missing fileId\")) {\n        LOGGER.severe(\"Upload response missing fileId. Check API version compatibility.\");\n        // Do not retry — same response will come back\n        throw e;\n    }\n    throw e;\n}","preventionTips":["Ensure the client library version matches the server API version.","When building mock servers, include {\"data\":{\"fileId\":\"test-id\"}} in upload responses.","Log the dataNode.toString() on validation failure to see what fields the server actually returns.","Check if the server renamed 'fileId' to 'id' or 'file_id' in a newer API version."],"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"}