remotion-dev/remotion · error

${err instanceof Error ? err.message : String(err)}

Error message

${err instanceof Error ? err.message : String(err)}

What it means

Generic error surfaced by the Next.js pages-router webhook handler when one of the onSuccess/onTimeout/onError callbacks throws. The thrown value is normalized to a string (Error.message if it is an Error, else String(err)) and returned as a JSON 500 response so the caller sees what failed inside the callback.

Source

Thrown at packages/lambda-client/src/pages-router-webhook.ts:62

				body: req.body,
				signatureHeader: req.headers['x-remotion-signature'] as string,
			});

			// If code reaches this path, the webhook is authentic.
			const payload = req.body as WebhookPayload;
			if (payload.type === 'success' && onSuccess) {
				await onSuccess(payload);
			} else if (payload.type === 'timeout' && onTimeout) {
				await onTimeout(payload);
			} else if (payload.type === 'error' && onError) {
				await onError(payload);
			}

			res.status(200).json({
				success: true,
			});
		} catch (err) {
			res.status(500).json({
				success: false,
				error: err instanceof Error ? err.message : String(err),
			});
		}
	};
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Inspect the 'error' field of the 500 JSON response to identify which callback threw and why.
  2. Wrap the body of your onSuccess/onTimeout/onError callbacks in try/catch so a callback failure does not surface as a 500.
  3. Log the full payload and callback error server-side for diagnosis, since only the message is returned.
  4. If the error is from an external service, add retries/backoff inside the callback.

Example fix

// before
const handler = startWebhookHandler({
  onSuccess: async (payload) => { await db.markDone(payload.renderId); }
});

// after
const handler = startWebhookHandler({
  onSuccess: async (payload) => {
    try { await db.markDone(payload.renderId); }
    catch (e) { logger.error('onSuccess failed', e); /* do not rethrow */ }
  }
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate payload shape before invoking callbacks
function isValidPayload(p: unknown): p is { type: string; renderId: string } {
  return typeof p === 'object' && p !== null
    && typeof (p as any).type === 'string'
    && typeof (p as any).renderId === 'string';
}
if (!isValidPayload(payload)) return res.status(400).json({ success: false, error: 'bad payload' });

Type guard

const isRenderPayload = (p: unknown): p is { type: 'success'|'timeout'|'error'; renderId: string } =>
  typeof p === 'object' && p !== null &&
  ['success','timeout','error'].includes((p as any).type) &&
  typeof (p as any).renderId === 'string';

Try / catch

// Each callback must swallow its own errors so the webhook returns 200
const safe = (fn) => async (payload) => {
  try { await fn(payload); }
  catch (e) { logger.error('webhook callback failed', e); }
};
onSuccess: safe(handleSuccess),

Prevention

When it happens

Trigger: Posting a render status payload (type 'success'|'timeout'|'error') to the webhook route, and the corresponding callback (onSuccess/onTimeout/onError) throws synchronously or returns a rejected promise.

Common situations: Webhook callback tries to write to a database that is unreachable; callback parses payload fields that are missing; third-party API call inside onSuccess fails; bug in user-supplied callback code; payload shape changed across versions.

Related errors


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