conductor-oss/conductor · error · IOException

OpenAI Video download failed with status %d: %s

Error message

OpenAI Video download failed with status %d: %s

What it means

Thrown by OpenAIVideoApi.downloadVideoStream when GET /v1/videos/{id}/content returns non-2xx. This is the streaming variant (returns InputStream); the response is manually closed on failure and the error body is captured. IOException message includes status code and body.

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIVideoApi.java:170

     * consume the stream. The stream wrapper closes the response when the stream is closed.
     *
     * @param videoId The video job ID
     * @return InputStream of the MP4 binary data
     */
    public InputStream downloadVideoStream(String videoId) throws IOException {
        Request request =
                new Request.Builder()
                        .url(baseUrl + "/v1/videos/" + videoId + "/content")
                        .header("Authorization", "Bearer " + apiKey)
                        .get()
                        .build();

        // Do not use try-with-resources here: the caller owns the stream lifecycle
        Response response = httpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            String errorBody = readResponseBody(response);
            response.close();
            throw new IOException(
                    "OpenAI Video download failed with status %d: %s"
                            .formatted(response.code(), errorBody));
        }

        ResponseBody body = response.body();
        if (body == null) {
            response.close();
            throw new IOException("OpenAI Video download returned empty body");
        }
        return body.byteStream();
    }

    /**
     * Download the completed video as a byte array.
     *
     * @param videoId The video job ID
     * @return byte array of the MP4 binary data
     */

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Only call download after getVideoStatus returns status='completed'.
  2. On 404/410, regenerate the video; the stored asset is gone.
  3. For 429, retry the download with backoff.
  4. If using the stream, ensure the caller closes the InputStream to release the connection.
Defensive patterns

Strategy: try-catch

Validate before calling

// Only attempt download once status is terminal-successful
VideoStatusResponse status = videoApi.getVideoStatus(videoId);
if (!"completed".equalsIgnoreCase(status.status())) {
    throw new IllegalStateException("Video not completed: " + status.status());
}

Try / catch

try (InputStream in = videoApi.downloadVideoStream(videoId)) {
    // consume stream, must close to release connection
} catch (IOException e) {
    if (e.getMessage().contains("status 404") || e.getMessage().contains("status 410")) {
        // asset gone - regenerate
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Downloading before the job status is 'completed' (400/409), the video asset has expired (404/410), invalid key (401), or rate limiting (429).

Common situations: Calling downloadVideoStream before getVideoStatus reports a terminal 'completed' state, waiting too long so the MP4 TTL expired, or a transient gateway error during the multi-minute download.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/fb476d641b04f467. Report an issue: GitHub.