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
- Re-parse the source and recompute the muted-attribute edit before applying it
- Ensure all edits in a run are captured from the same AST parse of the same input string
- Apply edits in a single batch (applySourceEdits) rather than reusing edits across mutations
- 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
- Capture all SourceEdits from one parse of the same input string
- Never reuse offsets after AST or source mutations — recompute them
- Apply batched edits via applySourceEdits instead of applying stale edits individually
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
- Could not locate the
- Could not locate the folder insertion target
- Could not locate the import prefix to update
- Overlapping source edit ranges
- A folder cannot be moved inside itself
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)