nexu-io/open-design · error · Error

grok task ${lastStatus}: ${reason}

Error message

grok task ${lastStatus}: ${reason}

What it means

Thrown when a Grok poll returns status 'failed' or 'expired'. This is xAI's definitive terminal-failure signal — the job was accepted and then xAI failed it (content policy, model error, expiry). The message interpolates lastStatus and a derived reason string (pollData.error.message, else pollData.error JSON-stringified, else lastStatus). Distinct from [477] (no answer in time) and [474] (transport rejection).

Source

Thrown at apps/daemon/src/media/index.ts:2396

      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;
        const reason = typeof reasonRaw === 'string' ? reasonRaw : JSON.stringify(reasonRaw);
        throw new Error(`grok task ${lastStatus}: ${reason}`);
      }
    }
    // Loop exited without a videoUrl. Distinguish the two reachable
    // cases so operators know which lever to pull: bumping the poll
    // 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) {

View on GitHub (pinned to 5be4028344)

Solutions

  1. Read the interpolated reason in the error message — xAI's error.message usually states the cause (content_policy, model_error).
  2. Rephrase the prompt / change the reference image for i2v and retry.
  3. Retry once — model crashes and false positives often succeed on a second attempt.
  4. If 'expired' and you can't make the job start faster, reduce requested duration or complexity so xAI completes before expiry.
  5. If persistent and the prompt is benign, file an xAI support ticket with the requestId.

Example fix

// before — terminal failure surfaces bare status
throw new Error(`grok task ${lastStatus}: ${reason}`);
// e.g. 'grok task failed: content_policy'

// caller — classify and retry on transient model_error
try {
  await renderGrokVideo(ctx, creds);
} catch (e) {
  if (/model_error|expired/.test(String(e.message))) await renderGrokVideo(ctx, creds);
  else throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

// Distinguish retryable terminal failures (model_error, expired) from
// non-retryable ones (content_policy) so callers retry sensibly.
try {
  await renderGrokVideo(ctx, creds, onProgress);
} catch (e) {
  const msg = String((e as Error).message || e);
  if (/grok task (failed|expired):/.test(msg)) {
    if (/model_error|expired|temporary|unknown/i.test(msg)) {
      await renderGrokVideo(ctx, creds, onProgress); // one retry
      return;
    }
    if (/content_policy|nsfw|safety/i.test(msg)) {
      throw new Error('Grok rejected the prompt on content-policy grounds. Rephrase and retry.');
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: Polling loop receives 200 with { status: 'failed' | 'expired', error?: ... }. Caused by prompts tripping xAI moderation, upstream model crashes, or jobs that sat in the queue past xAI's expiry window.

Common situations: Prompt contains content xAI blocks; i2v with a reference image xAI rejects; transient model crash; job queued so long it hit xAI's expiry; safety-filter false positive.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/1c2f2a4a1608355b. Report an issue: GitHub.