remotion-dev/remotion · error

Element source changed during installation

Error message

Element source changed during installation

What it means

Surfaced by insertElement in @remotion/browser-studio (as `{success: false, type: 'error', reason}`) when the caller passed a non-null `expectedFileState` that no longer matches the plan's actual file state, AND the plan has no `existingSource` (so the structured 'file-conflict' response is impossible). expectedFileState is an optimistic-concurrency token from prepareElementInstall: it proves the element file on disk is still in the state the client last saw. A mismatch means the element file changed by other means between prepare and install.

Source

Thrown at packages/browser-studio/src/browser-studio-operations.ts:2072

					request.expectedFileState !== null &&
					!expectedFileStateMatches({
						actual: plan.expectedFileState,
						expected: request.expectedFileState,
					})
				) {
					if (plan.existingSource !== null) {
						return {
							success: false,
							type: 'file-conflict',
							conflict: {
								existingSource: plan.existingSource,
								filePath: plan.filePath,
								incomingSource: request.element.sourceCode,
							},
						};
					}

					throw new Error('Element source changed during installation');
				}

				if (!request.overwriteExisting && plan.existingSource !== null) {
					return {
						success: false,
						type: 'file-conflict',
						conflict: {
							existingSource: plan.existingSource,
							filePath: plan.filePath,
							incomingSource: request.element.sourceCode,
						},
					};
				}

				const installedDependencies = await resolveElementDependencies(
					request.element.dependencies,
				);
				const installationMode = request.element.installationMode ?? 'wrapped';

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Re-run prepareElementInstall to get a fresh expectedFileState and repeat the install with it
  2. Pass `expectedFileState: null` to skip the staleness check when overwrite is acceptable
  3. Handle the 'file-conflict' response type (existingSource present) by asking the user to overwrite or keep both
  4. Avoid mutating element files while an install is in flight

Example fix

// before
await operations.insertElement({
  element,
  compositionFile,
  compositionId,
  expectedFileState: stalePlan.expectedFileState, // from an old prepare call
  overwriteExisting: false,
});

// after
const plan = await operations.prepareElementInstall({element, compositionFile, compositionId});
if (!plan.success) throw new Error(plan.reason);
const res = await operations.insertElement({
  element,
  compositionFile,
  compositionId,
  expectedFileState: plan.plan.expectedFileState, // fresh token
  overwriteExisting: false,
});
if (!res.success && res.type === 'file-conflict') {
  // ask user, then retry with overwriteExisting: true
}
Defensive patterns

Strategy: validation

Validate before calling

const plan = await operations.prepareElementInstall({element, compositionFile, compositionId});
if (!plan.success) throw new Error(plan.reason);
// use the fresh token; pass null to skip the check when overwriting is fine
const res = await operations.insertElement({element, compositionFile, compositionId, expectedFileState: plan.plan.expectedFileState, overwriteExisting: false});
if (!res.success && res.type === 'file-conflict') { /* ask user, retry with overwriteExisting: true */ }

Prevention

When it happens

Trigger: Calling `insertElement({element, compositionFile, compositionId, expectedFileState, ...})` where expectedFileState came from an earlier prepareElementInstall and the target file has since been edited, restored, or re-scaffolded; passing an expectedFileState belonging to a different element file path.

Common situations: User edits the element file in an editor between previewing and installing the Element; two installs of related Elements race; an undo restored an older version of the element file mid-install.

Related errors


AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09). Data as JSON: /api/errors/9151a04e7855490f. Report an issue: GitHub.