nexu-io/open-design · error · Error
grok poll ${pollResp.status}: ${truncate(pollText, 240)}
Error message
grok poll ${pollResp.status}: ${truncate(pollText, 240)} What it means
Thrown inside the Grok polling loop when GET {baseUrl}/videos/{requestId} returns a non-2xx status. The message includes the HTTP status and the first 240 chars (truncated) of the poll body so the operator can read xAI's reason. Distinct from [475] (parse error), [476] (terminal failed/expired status), and [477] (timeout): this is the transport-level rejection of a single poll.
Source
Thrown at apps/daemon/src/media/index.ts:2376
if (!videoUrl && requestId) {
const startedAt = Date.now();
const configuredMaxMs = Number(process.env.OD_GROK_VIDEO_MAX_POLL_MS);
const maxMs =
Number.isFinite(configuredMaxMs) && configuredMaxMs >= 60_000
? configuredMaxMs
: 8 * 60 * 1000;
if (typeof onProgress === 'function') {
const mode = ctx.imageRef ? 'i2v' : 't2v';
onProgress(`grok ${mode} task ${requestId} accepted; polling status…`);
}
while (Date.now() - startedAt < maxMs) {
await sleep(4000);
const pollResp = await fetch(`${baseUrl}/videos/${encodeURIComponent(requestId)}`, withMediaRequestInit(ctx, {
headers: { 'authorization': `Bearer ${credentials.apiKey}` },
}));
const pollText = await pollResp.text();
if (!pollResp.ok) {
throw new Error(`grok poll ${pollResp.status}: ${truncate(pollText, 240)}`);
}
let pollData: any;
try {
pollData = JSON.parse(pollText);
} catch {
throw new Error(`grok poll non-JSON: ${truncate(pollText, 200)}`);
}
lastStatus = pollData.status || '';
if (typeof onProgress === 'function') {
const elapsedSec = Math.round((Date.now() - startedAt) / 1000);
onProgress(`grok task ${requestId} status=${lastStatus || 'pending'} (elapsed ${elapsedSec}s)`);
}
if (lastStatus === 'done' || lastStatus === 'succeeded') {
videoUrl = pollData?.video?.url || null;
break;
}
if (lastStatus === 'failed' || lastStatus === 'expired') {
const reasonRaw = pollData?.error?.message || pollData?.error || lastStatus;View on GitHub (pinned to 5be4028344)
Solutions
- Read the truncated poll body in the error — xAI often includes a reason (rate_limited, not_found).
- If 429 persistent: the 4000ms poll interval may be too aggressive for your account tier; raise the interval or wait for quota reset.
- If 404: requestId is gone — resubmit the entire generation; if it 404s immediately, the submit returned a bogus id (see [478]).
- If 401/403: refresh the xAI credential and resubmit.
- If 5xx: retry the whole job after a short backoff.
Example fix
// before — single poll failure throws immediately
if (!pollResp.ok) {
throw new Error(`grok poll ${pollResp.status}: ${truncate(pollText, 240)}`);
}
// after — tolerate transient 5xx/429 within the poll ceiling
if (!pollResp.ok) {
if ((pollResp.status === 429 || pollResp.status >= 500) && Date.now() - startedAt < maxMs) {
await sleep(8000); // back off harder
continue;
}
throw new Error(`grok poll ${pollResp.status}: ${truncate(pollText, 240)}`);
} Defensive patterns
Strategy: retry
Try / catch
// Poll failures are dominated by transient 5xx/429; tolerate them inside the
// poll window, only throw on auth or definitive not-found.
while (Date.now() - startedAt < maxMs) {
await sleep(4000);
const pollResp = await fetch(`${baseUrl}/videos/${encodeURIComponent(requestId)}`, withMediaRequestInit(ctx, { headers: { authorization: `Bearer ${credentials.apiKey}` } }));
const pollText = await pollResp.text();
if (!pollResp.ok) {
if ((pollResp.status === 429 || pollResp.status >= 500) && Date.now() - startedAt < maxMs) { await sleep(8000); continue; }
throw new Error(`grok poll ${pollResp.status}: ${truncate(pollText, 240)}`);
}
// ... parse + handle
} Prevention
- Treat poll 5xx and 429 as retryable inside the ceiling; the current code throws on every non-2xx.
- Use a jittered backoff on 429 to avoid stampeding xAI's limiter.
- Track per-requestId poll status codes in logs; chronic 4xx mid-job signals key revocation.
When it happens
Trigger: Polling loop calls /videos/{id} and pollResp.ok is false — 401/403 (key lost scope mid-job), 404 (requestId doesn't exist or expired), 429 (rate-limit on polls), or 5xx (xAI outage). The poll loop sleeps 4000ms between attempts.
Common situations: Polling rate exceeded xAI's limit (429); requestId expired from xAI's retention before completion (404); API key revoked mid-job (401); transient xAI 5xx during the poll window.
Related errors
- leonardo.ai poll ${pollResp.status}
- grok video submit ${submitResp.status}: ${truncate(submitTex
- grok poll non-JSON: ${truncate(pollText, 200)}
- grok video fetch ${dlResp.status}
- no xAI credentials — sign in with your SuperGrok subscriptio
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/02c17d38020d212d.
Report an issue: GitHub.