{"record":{"id":"4740b79949aec38d","repo":"conductor-oss/conductor","slug":"openai-video-thumbnail-download-failed-with-status","errorCode":null,"errorMessage":"OpenAI Video thumbnail download failed with status %d","messagePattern":"OpenAI Video thumbnail download failed with status (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIVideoApi.java","lineNumber":226,"sourceCode":"    }\n\n    /**\n     * Download the thumbnail for a completed video.\n     *\n     * @param videoId The video job ID\n     * @return byte array of the thumbnail image (webp format)\n     */\n    public byte[] downloadThumbnail(String videoId) throws IOException {\n        Request request =\n                new Request.Builder()\n                        .url(baseUrl + \"/v1/videos/\" + videoId + \"/content?variant=thumbnail\")\n                        .header(\"Authorization\", \"Bearer \" + apiKey)\n                        .get()\n                        .build();\n\n        try (Response response = httpClient.newCall(request).execute()) {\n            if (!response.isSuccessful()) {\n                throw new IOException(\n                        \"OpenAI Video thumbnail download failed with status %d\"\n                                .formatted(response.code()));\n            }\n            ResponseBody body = response.body();\n            if (body == null) {\n                throw new IOException(\"OpenAI Video thumbnail download returned empty body\");\n            }\n            return body.bytes();\n        }\n    }\n\n    // -- Helpers --\n\n    /** Safely read the response body as a string, returning empty string if body is null. */\n    private String readResponseBody(Response response) throws IOException {\n        ResponseBody body = response.body();\n        return body != null ? body.string() : \"\";\n    }","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIVideoApi.java#L208-L244","documentation":"Thrown by OpenAIVideoApi.downloadThumbnail when GET /v1/videos/{id}/content?variant=thumbnail returns non-2xx. Message reports only the status code (no error body). This fetches the webp thumbnail associated with a completed video.","triggerScenarios":"Downloading a thumbnail before the video is complete (400/409), the video/thumbnail asset expired (404/410), invalid key (401), or rate limiting (429). Some completed jobs may not have a thumbnail.","commonSituations":"Calling downloadThumbnail before status is completed, thumbnail not generated for the job (404), or asset TTL elapsed.","solutions":["Ensure getVideoStatus() reports 'completed' before requesting the thumbnail.","On 404, treat the thumbnail as unavailable rather than retrying indefinitely.","For 429, back off before retrying."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Only fetch thumbnail after completion\nVideoStatusResponse status = videoApi.getVideoStatus(videoId);\nif (!\"completed\".equalsIgnoreCase(status.status())) {\n    throw new IllegalStateException(\"Video not completed: \" + status.status());\n}","typeGuard":null,"tryCatchPattern":"try {\n    byte[] thumb = videoApi.downloadThumbnail(videoId);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"status 404\")) {\n        // thumbnail not available - degrade gracefully (skip thumbnail)\n    } else {\n        throw e;\n    }\n}","preventionTips":["Ensure the video is completed before requesting the thumbnail.","Treat a 404 thumbnail as optional/missing rather than fatal.","Back off on 429 responses."],"tags":["openai","video","sora","http","download","thumbnail"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}