{"record":{"id":"4321ecb4efc334eb","repo":"conductor-oss/conductor","slug":"failed-to-submit-video-generation","errorCode":null,"errorMessage":"Failed to submit video generation: ","messagePattern":"Failed to submit video generation: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/openai/OpenAIVideoModel.java","lineNumber":92,"sourceCode":"                    new OpenAIVideoApi.VideoCreateParams(\n                            text, opts.getModel(), size, seconds, imageBytes, imageMimeType);\n\n            OpenAIVideoApi.VideoStatusResponse status = api.submitVideoJob(params);\n\n            log.info(\n                    \"OpenAI Sora video job submitted: id={}, status={}\",\n                    status.id(),\n                    status.status());\n\n            VideoResponseMetadata metadata = new VideoResponseMetadata();\n            metadata.setJobId(status.id());\n            metadata.setStatus(mapStatus(status.status()));\n\n            return new VideoResponse(List.of(), metadata);\n\n        } catch (Exception e) {\n            log.error(\"Failed to submit OpenAI video generation job\", e);\n            throw new RuntimeException(\"Failed to submit video generation: \" + e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public VideoResponse checkStatus(String jobId) {\n        try {\n            OpenAIVideoApi.VideoStatusResponse status = api.getVideoStatus(jobId);\n\n            VideoResponseMetadata metadata = new VideoResponseMetadata();\n            metadata.setJobId(status.id());\n            metadata.setStatus(mapStatus(status.status()));\n            metadata.put(\"progress\", status.progress());\n\n            if (\"completed\".equals(status.status())) {\n                // Download the video MP4 as bytes\n                // Use direct byte storage to avoid base64 encoding overhead (~33% memory savings)\n                byte[] videoBytes = api.downloadVideo(jobId);\n","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/openai/OpenAIVideoModel.java#L74-L110","documentation":"OpenAIVideoModel.call() catches a generic Exception and wraps it in a RuntimeException with message \"Failed to submit video generation: \". This is the async job-submission path for OpenAI Sora: POST /v1/videos. Any exception during job submission (API error, image resolution failure, JSON parse error, or IOException from submitVideoJob) is caught and rethrown. The catch is broad (Exception) because the method also resolves input images and detects MIME types.","triggerScenarios":"generateVideo() calls videoModel.call(videoPrompt) which submits a Sora job. Failure occurs when: invalid/expired API key, Sora not available for the account, invalid size or duration parameter, input image URL unreachable (see errors 214/215), malformed image data, or network error reaching the Sora API endpoint.","commonSituations":"API key without Sora access (Sora is a limited-access model); using a size OpenAI doesn't accept; image-to-video with a broken/expired image URL; Sora endpoint region mismatch; malformed base64 image input.","solutions":["Inspect getCause() for the root exception — it may be an IOException (API error), RuntimeException (image download), or IllegalArgumentException.","Verify the API key has Sora access (Sora requires specific account tier/allowlist).","Verify the model name is a valid Sora model (sora, sora-2, etc.).","If using image-to-video, verify the inputImage URL is reachable and valid (see errors 214, 215).","Verify size and duration match Sora's supported values (e.g. 1280x720, duration in seconds)."],"exampleFix":"// before\nVideoGenRequest req = new VideoGenRequest();\nreq.setInputImage(\"https://expired.example.com/img.jpg\"); // unreachable\n// after\nreq.setInputImage(\"https://valid-cdn.example.com/img.jpg\");","handlingStrategy":"try-catch","validationCode":"// Validate video generation request before submitting\nVideoGenRequest req = /* ... */;\nif (req.getModel() == null || req.getModel().isBlank()) {\n    throw new IllegalArgumentException(\"Video model name is required\");\n}\nif (req.getPrompt() == null || req.getPrompt().isBlank()) {\n    throw new IllegalArgumentException(\"Prompt is required for video generation\");\n}\n// If image-to-video, validate the input image URL is reachable\nif (req.getInputImage() != null && !req.getInputImage().isBlank()\n    && (req.getInputImage().startsWith(\"http://\") || req.getInputImage().startsWith(\"https://\"))) {\n    try {\n        URI uri = URI.create(req.getInputImage());\n        // Optionally do a HEAD request to check reachability\n    } catch (IllegalArgumentException e) {\n        throw new IllegalArgumentException(\"Invalid inputImage URL: \" + req.getInputImage());\n    }\n}","typeGuard":"null","tryCatchPattern":"try {\n    VideoResponse response = videoModel.call(prompt);\n} catch (RuntimeException e) {\n    Throwable cause = e.getCause();\n    String msg = cause != null ? cause.getMessage() : e.getMessage();\n    log.error(\"Video job submission failed: {}\", msg);\n    // If image download failed, fix the URL and retry\n    if (msg.contains(\"download image\") || msg.contains(\"Empty response\")) {\n        throw new IllegalArgumentException(\n            \"Input image URL is unreachable or returns empty. Use a data: URI instead.\", e);\n    }\n    throw e;\n}","preventionTips":["Verify the API key has Sora access before submitting video jobs.","Validate the input image URL is reachable from the worker before submission.","Convert input images to data: URIs to avoid network download failures.","Verify Sora size and duration parameters match supported values."],"tags":["openai","video-generation","sora","network","api-error","ai"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}