# Debugging "Frame Timeout" Errors in Remotion Renders: A Complete Guide

> Fix Remotion 'Frame timeout' errors. Learn how to resolve headless Chromium timeouts and delayRender issues for smoother video rendering. Get our complete debugging guide now.

- Repository: [Remotion/remotion](https://github.com/remotion-dev/remotion)
- Tags: how-to-guide
- Published: 2026-02-16

---

**A "Frame timeout" error occurs when Remotion's headless Chromium instance fails to complete navigation or finish `delayRender` calls within the configured timeout period, triggering a `TimeoutError` from the `LifecycleWatcher` class.**

When rendering compositions, the `remotion-dev/remotion` package spins up a headless browser via Puppeteer and monitors navigation lifecycle events. If the page load or component initialization exceeds the specified duration, the renderer throws a frame timeout error. Understanding the underlying mechanism in [`LifecycleWatcher.ts`](https://github.com/remotion-dev/remotion/blob/main/LifecycleWatcher.ts) and [`FrameManager.ts`](https://github.com/remotion-dev/remotion/blob/main/FrameManager.ts) is essential for diagnosing these failures.

## What Triggers a Frame Timeout Error?

Remotion renders work by navigating a headless Chromium browser to a page containing your component tree. During this process, the renderer creates a **`LifecycleWatcher`** instance that monitors browser lifecycle events (`load`, `domcontentloaded`, etc.) while simultaneously running a **timeout timer**.

If navigation does not complete before the timer expires, the watcher resolves with a **`TimeoutError`** defined in [`packages/renderer/src/browser/Errors.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/browser/Errors.ts). This error bubbles up through **`FrameManager.navigateFrame`** in [`packages/renderer/src/browser/FrameManager.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/browser/FrameManager.ts) and surfaces as the "Frame timeout" message in your logs.

## How the Timeout Mechanism Works

### The LifecycleWatcher Implementation

The core timeout logic resides in [`packages/renderer/src/browser/LifecycleWatcher.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/browser/LifecycleWatcher.ts). The private method `#createTimeoutPromise` sets up the timer that eventually triggers the error:

```typescript
// packages/renderer/src/browser/LifecycleWatcher.ts
private async #createTimeoutPromise(): Promise<TimeoutError | undefined> {
    if (!this.#timeout) {
        return new Promise(noop);
    }
    const errorMessage = 'Navigation timeout of ' + this.#timeout + ' ms exceeded';
    await new Promise((fulfill) => {
        this.#maximumTimer = setTimeout(fulfill, this.#timeout);
    });
    return new TimeoutError(errorMessage);
}

```

The `LifecycleWatcher` is instantiated inside `FrameManager.navigateFrame` with the timeout value passed from the renderer configuration:

```typescript
// packages/renderer/src/browser/FrameManager.ts
const watcher = new LifecycleWatcher(this, frame, waitUntil, timeout);

```

### Minimum Timeout Enforcement

Before the timeout reaches Chromium, Remotion validates it in [`packages/renderer/src/validate-puppeteer-timeout.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/validate-puppeteer-timeout.ts). The renderer enforces a hard minimum of **7000 milliseconds**:

```typescript
// packages/renderer/src/validate-puppeteer-timeout.ts
if (timeoutInMilliseconds < 7000 && process.env.NODE_ENV !== 'test') {
    throw new TypeError(
        `'timeoutInMilliseconds' should be bigger or equal than 7000, but is ${timeoutInMilliseconds}`,
    );
}

```

Attempting to set a timeout below 7000ms (except when `NODE_ENV=test`) immediately throws a `TypeError`, which can be mistaken for a frame timeout if not checked properly.

## Configuring the Timeout Duration

Remotion provides two methods to customize the navigation timeout, both managed through [`packages/renderer/src/options/timeout.tsx`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/options/timeout.tsx):

**CLI Flag** – Use `--timeout` with the render command (default: 30000ms):

```bash
remotion render MyComp.jsx out.mp4 --timeout 120000

```

**Programmatic API** – Import `setDelayRenderTimeoutInMilliseconds` before calling `renderMedia`:

```tsx
import {setDelayRenderTimeoutInMilliseconds, renderMedia} from 'remotion';

// Set timeout to 90 seconds
setDelayRenderTimeoutInMilliseconds(90_000);

await renderMedia({
  composition: MyComposition,
  serveUrl: 'http://localhost:3000',
  codec: 'h264',
  outputLocation: './out.mp4',
});

```

Both methods update the `currentTimeout` value that the renderer reads when creating the `LifecycleWatcher`.

## Common Causes of Frame Timeouts

- **Heavy component trees or long-running `delayRender`** – Complex initialization prevents navigation from reaching the expected lifecycle event before the timer fires.
- **Network-blocked resources** – Chromium waits for external fonts, images, or APIs, but the timeout continues running.
- **Sub-7s timeout values** – Violating the minimum threshold in [`validate-puppeteer-timeout.ts`](https://github.com/remotion-dev/remotion/blob/main/validate-puppeteer-timeout.ts) triggers immediate validation errors or premature timeouts.
- **Browser crashes or detachment** – If the Puppeteer instance crashes, the `LifecycleWatcher` never receives navigation events, causing the timeout to fire.

## How to Debug Frame Timeout Errors

1. **Inspect the error message** – It contains the exact timeout value that was exceeded (e.g., "Navigation timeout of 30000 ms exceeded").
2. **Check render logs** – Look for "Waiting for root component to load" to identify where navigation stalls.
3. **Increase the timeout** – Extend via CLI (`--timeout 120000`) or `setDelayRenderTimeoutInMilliseconds(120_000)`.
4. **Verify the minimum threshold** – Ensure your timeout is ≥ 7000ms unless running with `NODE_ENV=test`.
5. **Validate network resources** – Confirm all external assets are reachable; network issues manifest as navigation timeouts.
6. **Test without the minimum bound** – Set `NODE_ENV=test` temporarily to bypass the 7s limit and see if the render completes faster.

## Practical Code Examples

### Extending Timeout via CLI

```bash

# Allow 2 minutes for navigation and delayRender calls

remotion render src/Video.jsx out.mp4 --timeout 120000

```

### Programmatic Timeout Configuration

```tsx
// src/render.ts
import {renderMedia, setDelayRenderTimeoutInMilliseconds} from 'remotion';
import {MyComposition} from './MyComposition';

async function run() {
  // Extend to 90 seconds
  setDelayRenderTimeoutInMilliseconds(90_000);

  await renderMedia({
    composition: MyComposition,
    serveUrl: 'http://localhost:3000',
    codec: 'h264',
    outputLocation: './out.mp4',
    // Optional per-render override:
    // timeoutInMilliseconds: 90_000,
  });
}
run();

```

### Catching TimeoutError in Custom Renderers

```typescript
import {renderMedia} from 'remotion';
import {TimeoutError} from '@remotion/renderer/dist/browser/Errors';

try {
  await renderMedia({ /* configuration */ });
} catch (err) {
  if (err instanceof TimeoutError) {
    console.error('Frame timed out:', err.message);
    // Implement retry logic with increased timeout
  } else {
    throw err;
  }
}

```

## Summary

- **Frame timeouts** originate in [`LifecycleWatcher.ts`](https://github.com/remotion-dev/remotion/blob/main/LifecycleWatcher.ts) when navigation exceeds the configured duration before reaching lifecycle events.
- **Default timeout** is 30000ms (30 seconds), enforced by [`TimeoutSettings.ts`](https://github.com/remotion-dev/remotion/blob/main/TimeoutSettings.ts) and validated in [`validate-puppeteer-timeout.ts`](https://github.com/remotion-dev/remotion/blob/main/validate-puppeteer-timeout.ts) with a hard minimum of 7000ms.
- **Configuration** happens via `--timeout` CLI flag or `setDelayRenderTimeoutInMilliseconds()` from [`options/timeout.tsx`](https://github.com/remotion-dev/remotion/blob/main/options/timeout.tsx).
- ** debugging** requires checking error messages for exact millisecond values, verifying network resource availability, and ensuring timeout values meet the 7-second minimum threshold.
- **Error handling** can specifically catch `TimeoutError` from [`browser/Errors.ts`](https://github.com/remotion-dev/remotion/blob/main/browser/Errors.ts) to implement custom retry logic.

## Frequently Asked Questions

### What is the default frame timeout in Remotion?

The default timeout is **30000 milliseconds** (30 seconds), defined in [`packages/renderer/src/browser/TimeoutSettings.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/browser/TimeoutSettings.ts). If your composition takes longer to initialize or fetch resources, you must explicitly increase this value using the `--timeout` CLI flag or the `setDelayRenderTimeoutInMilliseconds` API.

### Why do I get a TypeError about timeout being less than 7000ms?

This occurs because [`packages/renderer/src/validate-puppeteer-timeout.ts`](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/validate-puppeteer-timeout.ts) enforces a minimum timeout of 7000ms to prevent unstable renders. If you need to bypass this validation (for testing only), set `NODE_ENV=test`. In production, always configure timeouts above this threshold.

### How do I distinguish between a network timeout and a slow component?

Check the render logs for "Waiting for root component to load" messages. If the error occurs before this message appears, Chromium is likely stuck fetching external resources (fonts, images, APIs). If it appears after, your component's `delayRender` calls or heavy initialization logic are the culprit. Increase the timeout and instrument your component with console logs to pinpoint the bottleneck.

### Can I catch frame timeout errors programmatically?

Yes. Import `TimeoutError` from `@remotion/renderer/dist/browser/Errors` (or `@remotion/renderer/src/browser/Errors` in development) and use `instanceof` checks to catch navigation-specific timeouts separately from other render failures. This allows you to implement automatic retries with exponential backoff or fallback compositions.