conductor-oss/conductor · error · RuntimeException

Failed to check video status:

Error message

Failed to check video status: 

What it means

OpenAIVideoModel.checkStatus() catches a generic Exception and wraps it in a RuntimeException with message "Failed to check video status: ". This is the polling path: GET /v1/videos/{jobId}. Any exception during status polling or result download (api.getVideoStatus, api.downloadVideo, api.downloadThumbnail) is caught and rethrown. The catch covers the entire method body including the completed-download branch.

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/openai/OpenAIVideoModel.java:149

            } else if ("failed".equals(status.status())) {
                metadata.setStatus("FAILED");
                metadata.setErrorMessage(
                        "OpenAI video generation failed: %s".formatted(status.toString()));
                log.error("OpenAI Sora video failed: id={}, response = {}", jobId, status);
                return new VideoResponse(List.of(), metadata);

            } else {
                // queued or in_progress
                metadata.setStatus("PROCESSING");
                log.debug(
                        "OpenAI Sora video in progress: id={}, progress={}%",
                        jobId, status.progress());
                return new VideoResponse(List.of(), metadata);
            }

        } catch (Exception e) {
            log.error("Failed to check OpenAI video status for job {}", jobId, e);
            throw new RuntimeException("Failed to check video status: " + e.getMessage(), e);
        }
    }

    /**
     * Maps OpenAI status strings to our canonical status values.
     *
     * <p>OpenAI uses: queued, in_progress, completed, failed
     */
    private String mapStatus(String openaiStatus) {
        return switch (openaiStatus) {
            case "completed" -> "COMPLETED";
            case "failed" -> "FAILED";
            default -> "PROCESSING";
        };
    }

    /**
     * Resolves an input image specification to raw bytes.

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect getCause() and jobId in the log — the catch logs "Failed to check OpenAI video status for job {jobId}".
  2. For transient network errors during polling, retry checkStatus() with backoff (the Conductor async video workflow already polls).
  3. Verify the jobId is still valid — if the job was submitted long ago, it may have been purged.
  4. If the download itself fails (large MP4), check network bandwidth and OkHttp read timeout configuration.

Example fix

// before: single checkStatus call with no retry
VideoResponse resp = videoModel.checkStatus(jobId);
// after: retry with backoff for transient failures
VideoResponse resp;
int attempts = 0;
while (true) {
    try {
        resp = videoModel.checkStatus(jobId);
        break;
    } catch (RuntimeException e) {
        if (++attempts >= 3) throw e;
        Thread.sleep(5000L * attempts);
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate jobId before polling
if (jobId == null || jobId.isBlank()) {
    throw new IllegalArgumentException("Job ID is required to check video status");
}
// Verify jobId format (OpenAI video IDs are typically alphanumeric with hyphens)
if (!jobId.matches("[a-zA-Z0-9_-]+")) {
    throw new IllegalArgumentException("Invalid job ID format: " + jobId);
}

Type guard

null

Try / catch

// checkStatus is inherently a polling operation — retry transient failures
int maxRetries = 3;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
    try {
        VideoResponse response = videoModel.checkStatus(jobId);
        return response;
    } catch (RuntimeException e) {
        if (attempt == maxRetries) throw e;
        Throwable cause = e.getCause();
        if (cause instanceof IOException || cause instanceof java.net.SocketTimeoutException) {
            log.warn("Transient error polling video job {} (attempt {}), retrying", jobId, attempt + 1);
            Thread.sleep(5000L * (attempt + 1));
            continue;
        }
        throw e;
    }
}

Prevention

When it happens

Trigger: checkVideoStatus() polls a job by jobId. Failure occurs when: the jobId is invalid or expired, the API key was revoked between submission and polling, network timeout downloading the large MP4 video binary, the video content endpoint returns an error, or a transient network blip during polling.

Common situations: Polling a job whose ID expired (OpenAI may purge old video records); network timeout downloading a large completed video; thumbnail download fails (though that path has its own try/catch); rate limit on status polling; API key revoked mid-job.

Related errors


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