nexu-io/open-design · error · Error
grok video submit returned no inline video and no request_id
Error message
grok video submit returned no inline video and no request_id to poll (status=${lastStatus || 'unknown'}) What it means
Thrown when the Grok submit step returned 2xx JSON but neither an inline video.url nor a pollable id (requestId). xAI's documented contract is either (a) finished video inline, or (b) {id, status:'pending'} stub to poll; getting neither is an upstream contract break. The message interpolates the last observed status (from submitData.status) to help pinpoint whether the response was malformed or a new shape.
Source
Thrown at apps/daemon/src/media/index.ts:2419
// ceiling (timeout) vs filing a bug against the upstream contract
// (status=done but no video.url).
if (!videoUrl) {
const elapsedSec = Math.round((Date.now() - startedAt) / 1000);
const ceilingSec = Math.round(maxMs / 1000);
throw new Error(
`grok video timed out after ${elapsedSec}s waiting for status=done `
+ `(last status: ${lastStatus || 'pending'}, ceiling ${ceilingSec}s). `
+ `If your jobs legitimately need longer, raise OD_GROK_VIDEO_MAX_POLL_MS.`,
);
}
}
if (!videoUrl) {
// Submit returned neither an inline video.url nor a request_id —
// upstream broke its own contract. Surfacing the last status helps
// pinpoint whether it was a transient API blip or a malformed
// response we should add a parser branch for.
throw new Error(
`grok video submit returned no inline video and no request_id to poll `
+ `(status=${lastStatus || 'unknown'})`,
);
}
const dlResp = await fetch(videoUrl, withMediaRequestInit(ctx));
if (!dlResp.ok) throw new Error(`grok video fetch ${dlResp.status}`);
const arr = await dlResp.arrayBuffer();
const bytes = Buffer.from(arr);
return {
bytes,
providerNote: `grok/${ctx.wireModel} · ${aspectRatio} · ${durationSec}s · ${bytes.length} bytes`,
suggestedExt: '.mp4',
};
}
function grokAspectFor(aspect?: string): string {View on GitHub (pinned to 5be4028344)
Solutions
- Reproduce the submit call with curl to capture the full response body and identify the new shape.
- If xAI added a new field for the pollable id, extend the extraction (submitData?.id || submitData?.request_id || submitData?.<newField>) in apps/daemon/src/media/index.ts around line ~2356.
- Confirm baseUrl points at the xAI API version your code targets.
- Retry once — a transient malformed response may not recur; if it does, file an xAI support ticket with the captured body.
Example fix
// before
const requestId = submitData?.id || submitData?.request_id || null;
// after — accept new shape + aid diagnosis
const requestId =
submitData?.id || submitData?.request_id || submitData?.data?.id || null;
if (!videoUrl && !requestId) {
throw new Error(
`grok video submit returned no inline video and no request_id to poll `
+ `(status=${lastStatus || 'unknown'}, body=${truncate(JSON.stringify(submitData), 240)})`,
);
} Defensive patterns
Strategy: type-guard
Type guard
// Narrow the parsed Grok submit response so a missing video+id is caught at the
// boundary with a typed, debuggable error.
interface GrokSubmitInline { video: { url: string }; status: string }
interface GrokSubmitPollable { id: string; status: string }
interface GrokSubmitRequestId { request_id: string; status: string }
function getGrokRequestId(d: unknown): string | null {
if (!d || typeof d !== 'object') return null;
const obj = d as Record<string, any>;
return (typeof obj.id === 'string' && obj.id) || (typeof obj.request_id === 'string' && obj.request_id) || null;
}
function getGrokInlineVideoUrl(d: unknown): string | null {
if (!d || typeof d !== 'object') return null;
const obj = d as Record<string, any>;
return (typeof obj.video?.url === 'string' && obj.video.url) || null;
} Try / catch
let videoUrl = getGrokInlineVideoUrl(submitData);
const requestId = getGrokRequestId(submitData);
if (!videoUrl && !requestId) {
throw new Error(
`grok video submit returned no inline video and no request_id to poll `
+ `(status=${(submitData as any)?.status || 'unknown'}, body=${truncate(JSON.stringify(submitData), 240)})`,
);
} Prevention
- Pin the xAI API version in baseUrl and document which version the parser was written against.
- When xAI ships API changes, update the extractor and parser together — never let one drift.
- Surface the raw submit body (truncated) on contract break so future regressions are debuggable from a single occurrence.
When it happens
Trigger: submitData parses OK but submitData.video.url, submitData.id, and submitData.request_id are all falsy. Happens if xAI ships an API change introducing a third response shape, or returns a soft-success with neither asset.
Common situations: xAI API version mismatch (baseUrl pinned to an older/newer version); xAI adds a new asynchronous handshake shape; malformed response from an upstream bug; an intermediate proxy rewriting the response.
Related errors
- grok image response had no data[0]
- grok image response missing b64_json/url
- leonardo.ai response missing generationId
- no xAI credentials — sign in with your SuperGrok subscriptio
- grok image ${resp.status}: ${truncate(text, 240)}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/7fd53883831fa225.
Report an issue: GitHub.