remotion-dev/remotion · error · Error

Server returned status ${res.status} while fetching ${actual

Error message

Server returned status ${res.status} while fetching ${actualSrc}

What it means

During a server render, `<OffthreadVideo>` fetches the extracted frame as a binary blob from the Remotion media-extraction endpoint. If the HTTP response status is anything other than 200 (and not a 500 with a parsed error body), this generic error is thrown with the status code and the resolved source URL.

Source

Thrown at packages/core/src/video/OffthreadVideoForRendering.tsx:206

			try {
				const res = await fetch(actualSrc, {
					signal: controller.signal,
					cache: 'no-store',
				});
				if (res.status !== 200) {
					if (res.status === 500) {
						const json = await res.json();
						if (json.error) {
							const cleanedUpErrorMessage = (json.error as string).replace(
								/^Error: /,
								'',
							);

							throw new Error(cleanedUpErrorMessage);
						}
					}

					throw new Error(
						`Server returned status ${res.status} while fetching ${actualSrc}`,
					);
				}

				const blob = await res.blob();

				const url = URL.createObjectURL(blob);
				cleanup.push(() => URL.revokeObjectURL(url));
				setImageSrc({
					src: url,
					handle: newHandle,
				});
			} catch (err) {
				// If component is unmounted, we should not throw
				if ((err as Error).message.includes('aborted')) {
					continueRender(newHandle);
					return;
				}

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Verify the `src` URL resolves from the render environment (curl it from the same host).
  2. Ensure the asset is reachable: serve it via `staticFile` or an absolute public URL.
  3. Check the server logs for the matching request to see the underlying cause.
  4. If intermittent, pass `onError` to `<OffthreadVideo>` to capture the failure rather than aborting the render.

Example fix

// before
<OffthreadVideo src="https://broken.example.com/missing.mp4" />
// after
<OffthreadVideo src={staticFile('video.mp4')} />
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate reachability before render
const res = await fetch(src, {method: 'HEAD'});
if (!res.ok) throw new Error(`Asset not reachable: ${res.status} for ${src}`);

Type guard

const isHttpOk = (status: number): boolean => status >= 200 && status < 300;

Try / catch

try {
  await renderMedia(...);
} catch (err) {
  if (/Server returned status/.test((err as Error).message)) {
    // surface asset URL / status to operator, retry or swap asset
  }
}

Prevention

When it happens

Trigger: The frame-extraction server endpoint returns 4xx (e.g. asset not found, 404) or an unexpected 5xx, or the media URL is unreachable / misconfigured.

Common situations: Asset URL is wrong or not served by the render server, CORS or auth blocks the fetch, the source video is corrupt and the extractor fails partway, or running in an environment with restricted network egress.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/1246808d94787ed3. Report an issue: GitHub.