remotion-dev/remotion · error · Error

Muted attribute edit is outside the video element

Error message

Muted attribute edit is outside the video element

What it means

Thrown by applyEditToElementSource when the computed muted-attribute SourceEdit lies outside the byte range of the video JSXElement in the source (edit.start < element start or edit.end > element end). This is an internal consistency check: the edit being applied belongs to a different element or stale offsets. It protects against corrupting surrounding code with a misplaced splice.

Solutions

  1. Re-parse the source and recompute the muted-attribute edit before applying it
  2. Ensure all edits in a run are captured from the same AST parse of the same input string
  3. Apply edits in a single batch (applySourceEdits) rather than reusing edits across mutations
  4. Report a Remotion bug with the file and action that triggered it

Example fix

// before (stale edit applied to re-parsed input)
const ast2 = parseAst(newInput);
applyEditToElementSource({edit: staleEdit, element: findElement(ast2), input: newInput});
// after (recompute edit against the same parse)
const ast2 = parseAst(newInput);
const el = findElement(ast2);
const freshEdit = getMutedAttributeEdit({element: el, input: newInput});
applyEditToElementSource({edit: freshEdit, element: el, input: newInput});
Defensive patterns

Strategy: try-catch

Validate before calling

const within = (edit: SourceEdit, el: JSXElement, input: string) => {
  if (!el.loc) return false;
  const start = recastLocToOffset(input, el.loc.start);
  const end = recastLocToOffset(input, el.loc.end);
  return edit.start >= start && edit.end <= end;
};

Try / catch

try {
  const source = applyEditToElementSource({edit, element, input});
} catch (e) {
  if (e instanceof Error && e.message.includes('outside the video element')) {
    // recompute the muted edit against a fresh parse of the same input
    const fresh = computeMutedEdit(parseAst(input), input);
    return applyEditToElementSource({edit: fresh, element, input});
  }
  throw e;
}

Prevention

When it happens

Trigger: The SourceEdit computed for the muted attribute has offsets that don't fall within the video element's [start, end) range — e.g. the edit was derived from a different AST node, a stale element after the AST was mutated, or an offset mapping bug after source transformations.

Common situations: Chained codemod runs where the first mutation invalidates captured offsets, applying edits captured against one parse to a re-parsed source, or UI actions racing with file edits so the input string changed between parse and edit application.

Related errors


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

Appendix: source

Thrown at packages/studio-codemods/src/split-video-from-audio.ts:248

};

const applyEditToElementSource = ({
	edit,
	element,
	input,
}: {
	edit: SourceEdit;
	element: JSXElement;
	input: string;
}) => {
	if (!element.loc) {
		throw new Error('Could not locate the video element');
	}

	const start = recastLocToOffset(input, element.loc.start);
	const end = recastLocToOffset(input, element.loc.end);
	if (edit.start < start || edit.end > end) {
		throw new Error('Muted attribute edit is outside the video element');
	}

	const source =
		input.slice(start, edit.start) +
		edit.replacement +
		input.slice(edit.end, end);
	const originalIndent = getLineIndent({input, offset: start});
	return source
		.split(/\r?\n/)
		.map((line, index) => {
			if (index === 0) {
				return line;
			}

			return line.startsWith(originalIndent)
				? line.slice(originalIndent.length)
				: line.trimStart();
		})

View on GitHub (pinned to 46a3a6bf13)