remotion-dev/remotion · error · Error

Invalid ElevenLabs transcript. The transcript must be genera

Error message

Invalid ElevenLabs transcript. The transcript must be generated with `timestamps_granularity` set to `"word"`. See https://www.remotion.dev/docs/elevenlabs/elevenlabs-transcript-to-captions

What it means

The `elevenLabsTranscriptToCaptions` function expects an ElevenLabs transcript object with a `words` array, which is only present when the ElevenLabs API was called with `timestamps_granularity` set to `"word"`. If the transcript is null, missing the `words` field, or `words` is not an array, this error is thrown. This typically happens when the transcript was generated with character-level or no granularity.

Source

Thrown at packages/elevenlabs/src/elevenlabs-transcript-to-captions.ts:18

import type {Caption} from '@remotion/captions';
import type {ElevenLabsTranscript} from './elevenlabs-transcript';

export type ElevenLabsTranscriptToCaptionsInput = {
	transcript: ElevenLabsTranscript;
};

export type ElevenLabsTranscriptToCaptionsOutput = {
	captions: Caption[];
};

export const elevenLabsTranscriptToCaptions = ({
	transcript,
}: ElevenLabsTranscriptToCaptionsInput): ElevenLabsTranscriptToCaptionsOutput => {
	const captions: Caption[] = [];

	if (!transcript || !transcript.words || !Array.isArray(transcript.words)) {
		throw new Error(
			'Invalid ElevenLabs transcript. The transcript must be generated with `timestamps_granularity` set to `"word"`. See https://www.remotion.dev/docs/elevenlabs/elevenlabs-transcript-to-captions',
		);
	}

	const {words} = transcript;

	let isFirst = true;

	for (let i = 0; i < words.length; i++) {
		const entry = words[i];

		if (entry.type !== 'word') {
			continue;
		}

		const prevEntry = i > 0 ? words[i - 1] : null;
		const hasSpacing = prevEntry !== null && prevEntry.type === 'spacing';

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Regenerate the transcript with the ElevenLabs API using `timestamps_granularity: 'word'`.
  2. Verify the transcript object has a `words` array before calling the function.
  3. If using a different provider, convert its output to the ElevenLabs transcript shape with a `words` array first.

Example fix

// before
const result = await fetch('https://api.elevenlabs.io/v1/speech-to-text', { ... });
elevenLabsTranscriptToCaptions({ transcript: result });

// after
// Set timestamps_granularity to 'word' in the API request
elevenLabsTranscriptToCaptions({ transcript: result }); // now has .words array
Defensive patterns

Strategy: type-guard

Validate before calling

if (!transcript || !Array.isArray(transcript.words)) {
  throw new Error('Transcript was not generated with word-level timestamps');
}
const {captions} = elevenLabsTranscriptToCaptions({ transcript });

Type guard

const isWordLevelTranscript = (t: unknown): t is { words: unknown[] } =>
  typeof t === 'object' &&
  t !== null &&
  'words' in t &&
  Array.isArray((t as { words: unknown }).words);

Try / catch

try {
  const {captions} = elevenLabsTranscriptToCaptions({ transcript });
} catch (err) {
  if (err instanceof Error && err.message.includes('timestamps_granularity')) {
    // re-request transcript with word-level granularity
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling the function with a transcript from an ElevenLabs API call that used `timestamps_granularity: 'char'`, passing a speech-to-text result from a different provider, or passing an empty/null transcript object.

Common situations: Copying an ElevenLabs API response without setting the granularity parameter, switching from character-level to word-level captions without regenerating the transcript, or passing a Deepgram/Whisper result instead of ElevenLabs.

Related errors


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