R RenderComp
remotion troubleshooting debugging rendering errors

How to Fix Common Remotion Rendering Errors: A Troubleshooting Guide

How to Fix Common Remotion Rendering Errors: A Troubleshooting Guide

Most Remotion rendering problems come from a small set of causes, and each has a clear fix once you know what to look for. The frame preview looks fine in Remotion Studio, but the rendered video times out, freezes on a black frame, or ships without your fonts. Almost always, the culprit is one of a handful of patterns: an unreleased render delay, CSS animation that Remotion does not evaluate, assets referenced the wrong way, video drawn with the wrong component, or a memory limit hit during rendering.

This guide walks through the most common Remotion rendering errors, explains why each happens, and gives you the fix. Work through it top to bottom, or jump to the symptom that matches yours.


1. The Render Times Out

Symptom: The render fails with a timeout error, often mentioning a delayRender() handle.

Cause: When you call delayRender() to wait for async work, you must call continueRender() within the timeout — 30 seconds by default. If a code path never releases the handle (frequently an error branch that forgets to), the render hangs until it times out.

Fix: Make sure every delayRender() is matched by a continueRender(), including inside catch blocks. Call cancelRender(error) on failure so the render ends immediately with a useful message instead of hanging:

import { useDelayRender } from "remotion";

const { delayRender, continueRender, cancelRender } = useDelayRender();

const load = async () => {
  const handle = delayRender("Loading data");
  try {
    const data = await fetch("/api/data").then((r) => r.json());
    // ...use data...
    continueRender(handle);
  } catch (err) {
    cancelRender(err); // never leave the handle open
  }
};

If the work legitimately takes longer than 30 seconds, raise the limit with timeoutInMilliseconds on delayRender(). See remotion.dev/docs/timeout.


2. Animations Do Not Move in the Render

Symptom: Your animation plays in the browser preview but appears frozen — or only shows its final state — in the rendered video.

Cause: You animated with CSS transitions, CSS keyframe animations, or a Tailwind animation class. Remotion renders each frame as an independent snapshot; it does not run wall-clock CSS animation between frames, so those never render correctly.

Fix: Drive all motion from the current frame. Read useCurrentFrame() and map it to a value with interpolate():

import { useCurrentFrame, interpolate } from "remotion";

export const FadeIn: React.FC = () => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 30], [0, 1], {
    extrapolateRight: "clamp",
  });
  return <div style={{ opacity }}>Hello</div>;
};

Every visual property that changes over time must be a function of the frame. Remove transition:, @keyframes, and animation utility classes from anything you want to render.


3. Images or Assets Do Not Load

Symptom: Images, audio, or video are missing in the render, or the render errors on a file path that “exists.”

Cause: The asset was referenced with a relative or imported path that works in dev but not during rendering. Remotion serves local assets from the public/ folder, and you must reference them with staticFile().

Fix: Put the asset in public/ at the project root and reference it with staticFile():

import { Img, staticFile } from "remotion";

export const Logo = () => (
  <Img src={staticFile("logo.png")} style={{ width: 200 }} />
);

For files in nested folders, pass the path relative to public/ (for example, staticFile("brand/logo.png")). Remote URLs work directly and do not need staticFile(). See remotion.dev/docs/staticfile.


4. Video Renders as Black Frames

Symptom: An embedded video shows correctly in preview but comes out black or frozen in the rendered output.

Cause: A plain HTML <video> tag was used. During rendering, Remotion needs a component that seeks to the exact frame; a raw <video> element does not stay in sync frame-by-frame.

Fix: Use Remotion’s media components instead of the HTML tag. Use <OffthreadVideo> from remotion, or the <Video> component from @remotion/media, so each frame is extracted at the right timestamp:

import { OffthreadVideo, staticFile } from "remotion";

export const Clip = () => (
  <OffthreadVideo src={staticFile("broll.mp4")} muted />
);

Add muted when the clip’s audio should not be mixed into your video — a common source of unexpected audio bleed when reusing clips.


5. Fonts Flash or Are Missing

Symptom: Text renders in a fallback font, or the correct font appears only in some frames.

Cause: The font had not finished loading when the frame was captured. Font loading is asynchronous, and the render did not wait for it.

Fix: Load fonts in a way the render waits for. The simplest option is @remotion/google-fonts, which handles loading for you. For custom local fonts loaded via the FontFace API, wrap the load in delayRender()/continueRender() so Remotion holds the frame until the font is ready:

import { useDelayRender, staticFile } from "remotion";
import { useEffect } from "react";

const { delayRender, continueRender } = useDelayRender();

useEffect(() => {
  const handle = delayRender("Loading font");
  const font = new FontFace(
    "Brand",
    `url(${staticFile("Brand.woff2")})`
  );
  font.load().then(() => {
    document.fonts.add(font);
    continueRender(handle);
  });
}, []);

6. Out of Memory or Crashes at Scale

Symptom: The render crashes, especially on AWS Lambda or with long, high-resolution, or asset-heavy compositions.

Cause: The render exceeded the available memory or disk. Lambda functions have configurable memory and ephemeral storage limits, and video-heavy compositions are demanding.

Fix: For local renders, close other heavy processes and consider rendering in chunks. For @remotion/lambda, increase the function’s configured memory and disk size when you deploy it, and reduce the concurrency per function if needed. Prefer <OffthreadVideo> over embedding many simultaneous <video> elements, since it is designed to be more memory-efficient during rendering. If a single composition is extremely long, splitting it into segments and concatenating the outputs afterward reduces peak memory. See the Lambda and troubleshooting docs at remotion.dev/docs.


7. Audio Is Missing from the Output

Symptom: The video renders but has no sound, or a clip’s audio is unexpectedly present.

Cause: Audio was added with a raw <audio> tag (which does not sync during render), or a video clip was embedded without muting when its audio should have been silenced.

Fix: Add audio with the <Audio> component from @remotion/media and reference the file with staticFile(). When you only want a video’s visuals, add muted to the video component so its embedded audio does not leak into your mix:

import { Audio } from "@remotion/media";
import { staticFile } from "remotion";

export const WithSound = () => <Audio src={staticFile("voiceover.mp3")} />;

Quick Reference

SymptomLikely causeFix
Render times outcontinueRender() never calledMatch every delayRender(); cancelRender() on error
Animation frozenCSS/Tailwind animationUse useCurrentFrame() + interpolate()
Assets missingWrong pathPut in public/, use staticFile()
Black video framesRaw <video> tagUse <OffthreadVideo> / @remotion/media
Wrong or flashing fontsFont not awaited@remotion/google-fonts or delayRender()
Out of memoryLimit exceededIncrease Lambda memory/disk; render in chunks
No audio / audio bleedRaw <audio> or unmuted clip<Audio> from @remotion/media; add muted

FAQ

Q: Why does my Remotion animation work in preview but not in the render? You are almost certainly animating with CSS transitions, CSS keyframes, or a Tailwind animation class. Remotion renders each frame independently and does not evaluate wall-clock CSS animation. Drive all motion from useCurrentFrame() with interpolate() instead.

Q: Why does my Remotion render keep timing out? The usual cause is a delayRender() handle that is never released by continueRender(), often in an error branch. Ensure every handle is matched, call cancelRender(error) in catch blocks, and raise timeoutInMilliseconds only if the async work legitimately exceeds 30 seconds.

Q: Why are my images not showing up in the rendered video? Local assets must live in the public/ folder and be referenced with staticFile(). Relative or imported paths that work in development can fail during rendering. Remote URLs can be used directly.

Q: Why is my embedded video black in the output? You likely used a raw HTML <video> tag, which does not seek frame-by-frame during rendering. Use <OffthreadVideo> from remotion or <Video> from @remotion/media so each frame is extracted at the correct timestamp.

Q: How do I stop fonts from flashing or falling back? Ensure the render waits for the font to load. Use @remotion/google-fonts, or for custom fonts loaded with FontFace, wrap the load in delayRender()/continueRender() so Remotion holds the frame until the font is ready.

Q: How do I fix out-of-memory errors on Lambda? Increase the configured memory and disk size on your Remotion Lambda function, reduce concurrency per function if needed, prefer <OffthreadVideo> for video, and split very long compositions into segments that you concatenate afterward.


Build Faster with RenderComp

Many rendering bugs come from wiring up assets, fonts, video, and data-loading correctly. RenderComp provides production-ready Remotion templates — intros, lower thirds, social formats, data visualizations, and more — built with the correct patterns (staticFile(), OffthreadVideo, proper data loading) already in place, and typed props ready for your render pipeline. Fewer footguns, faster to ship.

Browse the collection at rendercomp.com and start rendering on day one.

Now available

Get 1,000+ Remotion Templates

Pay once — no subscription. Lifetime updates. TypeScript-first.

View pricing →