vercel/ai · error

Video generation did not complete after webhook notification

Error message

Video generation did not complete after webhook notification.

What it means

After a webhook notification arrived, the subsequent (or final) doStatus call still did not report a completed (or failed) status, so the flow cannot produce a result. The SDK throws because it cannot reconcile the webhook event with the provider's status endpoint.

Source

Thrown at packages/ai/src/generate-video/generate-video.ts:598

    if (statusResult.providerMetadata != null) {
      operationProviderMetadata ??= {};
      mergeProviderMetadata(
        operationProviderMetadata,
        statusResult.providerMetadata,
      );
    }

    if (statusResult.status === 'completed') {
      return {
        videos: statusResult.videos,
        warnings: allWarnings,
        providerMetadata: operationProviderMetadata,
        response: statusResult.response,
      };
    }

    if (webhookReceived != null) {
      throw new Error(
        'Video generation did not complete after webhook notification.',
      );
    }
  }
}

async function waitForWebhook({
  received,
  timeoutMs,
  abortSignal,
  delay,
}: {
  received: PromiseLike<Experimental_VideoModelV4OperationWebhook>;
  timeoutMs: number;
  abortSignal?: AbortSignal;
  delay: (
    delayInMs: number,
    options?: { abortSignal?: AbortSignal },

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Re-check status after a short delay with experimental_getVideoStatus instead of assuming failure.
  2. Verify the webhookUrl endpoint is correct and the provider's webhook semantics match the SDK's expectations.
  3. Increase tolerance/retry the status check; treat it as transient if the provider is eventually consistent.
  4. If reproducible, report to the provider/SDK since the webhook and status endpoints disagree.

Example fix

// before
const { video } = await op; // may throw after webhook
// after
try {
  const { video } = await op;
} catch (e) {
  if (e.message.includes('webhook')) {
    const status = await experimental_getVideoStatus({ model, operation: op.operation }); // re-poll
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// ensure webhookUrl is a publicly reachable https endpoint before starting
new URL(webhookUrl); if (!webhookUrl.startsWith('https://')) throw new Error('webhookUrl must be public https');

Type guard

null

Try / catch

try {
  const { video } = await op;
} catch (e) {
  if (e.message.includes('webhook')) {
    // webhook arrived but status disagreed; re-poll before giving up
    const status = await experimental_getVideoStatus({ model, operation: op.operation });
  }
}

Prevention

When it happens

Trigger: executeStartStatusFlow with webhookUrl configured: waitForWebhook resolved (webhookReceived != null) but the polled statusResult still indicates a non-terminal/non-success state.

Common situations: Provider sends webhook events out of order or before its status API is consistent; webhook payload parsed but status endpoint lags; provider bug where webhook signals progress rather than completion; network caching of stale status responses.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/f8b4952240a387ce. Report an issue: GitHub.