{"record":{"id":"c29911d2509d73cd","repo":"conductor-oss/conductor","slug":"openai-video-download-returned-empty-body","errorCode":null,"errorMessage":"OpenAI Video download returned empty body","messagePattern":"OpenAI Video download returned empty body","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIVideoApi.java","lineNumber":178,"sourceCode":"                        .url(baseUrl + \"/v1/videos/\" + videoId + \"/content\")\n                        .header(\"Authorization\", \"Bearer \" + apiKey)\n                        .get()\n                        .build();\n\n        // Do not use try-with-resources here: the caller owns the stream lifecycle\n        Response response = httpClient.newCall(request).execute();\n        if (!response.isSuccessful()) {\n            String errorBody = readResponseBody(response);\n            response.close();\n            throw new IOException(\n                    \"OpenAI Video download failed with status %d: %s\"\n                            .formatted(response.code(), errorBody));\n        }\n\n        ResponseBody body = response.body();\n        if (body == null) {\n            response.close();\n            throw new IOException(\"OpenAI Video download returned empty body\");\n        }\n        return body.byteStream();\n    }\n\n    /**\n     * Download the completed video as a byte array.\n     *\n     * @param videoId The video job ID\n     * @return byte array of the MP4 binary data\n     */\n    public byte[] downloadVideo(String videoId) throws IOException {\n        Request request =\n                new Request.Builder()\n                        .url(baseUrl + \"/v1/videos/\" + videoId + \"/content\")\n                        .header(\"Authorization\", \"Bearer \" + apiKey)\n                        .get()\n                        .build();\n","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIVideoApi.java#L160-L196","documentation":"Thrown by OpenAIVideoApi.downloadVideoStream when the content endpoint returns 2xx but response.body() is null. The response is closed before throwing. A defensive guard for abnormal proxy/gateway behavior on a binary endpoint.","triggerScenarios":"A proxy or gateway strips the MP4 body while forwarding a 200, or an OkHttp interceptor consumes the body before downloadVideoStream reads it.","commonSituations":"Corporate proxy rewriting binary responses, a misconfigured CDN, or a shared httpClient with logging interceptors that fully drain large bodies.","solutions":["Call OpenAI directly bypassing proxies to confirm the body is present.","Audit OkHttp interceptors on the shared client for premature body reads.","Ensure the gateway passes through the binary content type and body unchanged."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try (InputStream in = videoApi.downloadVideoStream(videoId)) {\n    // consume\n} catch (IOException e) {\n    if (e.getMessage().contains(\"empty body\")) {\n        // proxy stripped the body; try the direct endpoint\n    } else {\n        throw e;\n    }\n}","preventionTips":["Avoid OkHttp interceptors that consume response bodies.","Verify proxies forward binary content unchanged.","Test downloads against the direct OpenAI endpoint first."],"tags":["openai","video","sora","download","empty-body","proxy"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}