remotion-dev/remotion · error · Error

Pass at least one subset to loadVariableFont()

Error message

Pass at least one subset to loadVariableFont()

What it means

loadVariableFont() loads a Google variable font but requires the caller to explicitly list which Unicode subsets (e.g. 'latin', 'cyrillic') to load. The library throws this error when options.subsets is an empty array, because loading zero subsets would produce no usable @font-face resources. It is a fail-fast validation of a required, non-empty option.

Solutions

  1. Pass at least one valid subset name in options.subsets, e.g. {subsets: ['latin']}
  2. Check which subsets the font actually supports via the font's metadata (meta.subsets) and include the ones you need
  3. If subsets are computed dynamically, validate the array is non-empty (or fall back to ['latin']) before calling

Example fix

// before
await loadVariableFont(font, {style: 'normal', subsets: []});
// after
await loadVariableFont(font, {style: 'normal', subsets: ['latin']});
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(options.subsets) || options.subsets.length === 0) {
  throw new Error('loadVariableFont() requires at least one subset, e.g. ["latin"]');
}

Type guard

function hasSubsets(o: {subsets?: string[]} | null): o is {subsets: string[]} {
  return !!o && Array.isArray(o.subsets) && o.subsets.length > 0;
}

Try / catch

try {
  await loadVariableFont(font, {style: 'normal', subsets});
} catch (e) {
  if ((e as Error).message.includes('Pass at least one subset')) {
    await loadVariableFont(font, {style: 'normal', subsets: ['latin']});
  } else throw e;
}

Prevention

When it happens

Trigger: Calling loadVariableFont() (via loadVariableFonts) with an options object whose subsets property is [], e.g. loadVariableFont(meta, {subsets: [], style: 'normal'}), typically because subsets were built dynamically from a filter or variable that resolved to nothing.

Common situations: Deriving subsets from user config or metadata where the list ends up empty (e.g. filtering subsets that no longer exist in the current @remotion/google-fonts version); copy-pasting the function call and forgetting to fill in subsets; generating the call from code that emits an empty array literal.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18). Data as JSON: /api/errors/302cc2694c2a3e9b. Report an issue: GitHub.

Appendix: source

Thrown at packages/google-fonts/src/base.ts:263

		waitUntilDone: () => Promise.all<void>(promises).then(() => undefined),
	};
};

export const loadVariableFonts = (
	meta: FontInfo,
	style: string,
	options: FontLoadOptions & {subsets: string[]},
): {
	fontFamily: FontInfo['fontFamily'];
	axes: Record<string, {min: number; max: number}>;
	waitUntilDone: () => Promise<undefined>;
} => {
	if (!meta.variable) {
		throw new Error(`${meta.fontFamily} is not available as a variable font`);
	}

	if (options.subsets.length === 0) {
		throw new Error('Pass at least one subset to loadVariableFont()');
	}

	const fontFacesForStyle = meta.variable.fontFaces.filter(
		(fontFace) => fontFace.style === style,
	);
	if (fontFacesForStyle.length === 0) {
		throw new Error(
			`The variable font ${meta.fontFamily} does not have a style ${style}`,
		);
	}

	const availableSubsetKeys = fontFacesForStyle.map(
		(fontFace) => fontFace.subset,
	);
	const subsets = [
		...new Set(
			options.subsets.flatMap((requestedSubset) =>
				resolveFontSubsetKeys({

View on GitHub (pinned to 46a3a6bf13)