remotion-dev/remotion · error · Error

onError was used but did not return an "action" field. See…

Error message

onError was used but did not return an "action" field. See docs for this API on how to use onError.

What it means

When a parse iteration throws and an onError callback was supplied, parseLoop awaits onError(e) and inspects the returned object. If that object has no `action` field the parser throws, because it cannot decide whether to fail or continue. The contract requires onError to return `{action: 'fail' | 'download'}`.

Solutions

  1. Make onError return an object with action: `{action: 'fail'}` to re-throw, or `{action: 'download'}` to continue parsing.
  2. If you only want to log, return `{action: 'fail'}` after logging so the original error still propagates.
  3. Add a TypeScript annotation `onError: ParseMediaOnError` so a missing action is caught at compile time.
  4. Read the media-parser onError docs for the full return contract.

Example fix

// before
await parseMedia({src, onError: (e) => console.error(e), fields: {}});

// after
await parseMedia({
  src,
  onError: (e) => {
    console.error(e);
    return {action: 'fail'};
  },
  fields: {},
});
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate your onError returns the right shape before passing it in
function makeOnError(log: (e: Error) => void) {
  return (e: Error): {action: 'fail' | 'download'} => {
    log(e);
    return {action: 'fail'};
  };
}

Type guard

import type {ParseMediaOnError} from '@remotion/media-parser';
const isOnErrorResult = (v: unknown): v is {action: 'fail' | 'download'} =>
  typeof v === 'object' && v !== null &&
  (v as any).action === 'fail' || (v as any).action === 'download';

Try / catch

// Not applicable — this error IS the result of a bad onError contract.
// Fix: ensure onError always returns {action: 'fail' | 'download'}.
await parseMedia({
  src,
  onError: (e) => { console.error(e); return {action: 'fail'}; },
  fields: {},
});

Prevention

When it happens

Trigger: Supplying an onError that returns undefined, null, `{}`, or an object missing the action key — e.g. `onError: (e) => console.error(e)` (returns undefined) or `onError: () => ({retry: true})`.

Common situations: Treating onError like a logging callback instead of a recovery decision function; copy-pasting from examples that omit the return; migration from an older API shape.

Related errors


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

Appendix: source

Thrown at packages/media-parser/src/parse-loop.ts:149

						iterator: state.iterator,
						logLevel: state.logLevel,
						mode: state.mode,
						contentLength: state.contentLength,
						seekInfiniteLoop: state.seekInfiniteLoop,
						currentReader: state.currentReader,
						readerInterface: state.readerInterface,
						fields: state.fields,
						src: state.src,
						discardReadBytes: state.discardReadBytes,
						prefetchCache: state.prefetchCache,
						isoState: state.iso,
					});
					state.timings.timeSeeking += Date.now() - seekStart;
				}
			} catch (e) {
				const err = await onError(e as Error);
				if (!err.action) {
					throw new Error(
						'onError was used but did not return an "action" field. See docs for this API on how to use onError.',
					);
				}

				if (err.action === 'fail') {
					throw e;
				}

				if (err.action === 'download') {
					state.errored = e as Error;
					Log.verbose(
						state.logLevel,
						'Error was handled by onError and deciding to continue.',
					);
				}
			}
		}

View on GitHub (pinned to 78fe4bb3fd)