remotion-dev/remotion · error

A skill is already being installed or removed. Please try…

Error message

A skill is already being installed or removed. Please try again once it finishes.

What it means

changeRemotionSkill serializes skill install/remove operations per Remotion project using a `changingSkillsInProjects` set. If a skill change is already in flight for the same remotionRoot, a second concurrent request is rejected with this error so two package-manager operations never interleave on one project. The message tells the caller to wait and retry.

Solutions

  1. Wait for the in-progress install/remove to finish (watch the Studio UI progress indicator), then retry
  2. Debounce or serialize requests in client code so only one skill change runs at a time per project
  3. Reload the Studio page if the previous operation is believed to have crashed and left the lock stuck

Example fix

// before: parallel requests
await Promise.all([installSkill('a'), installSkill('b')])
// after: sequential
await installSkill('a');
await installSkill('b');
Defensive patterns

Strategy: retry

Validate before calling

// track in-flight operations client-side
let inFlight = false;
if (inFlight) throw new Error('A skill change is already running');

Try / catch

try {
  await installSkill(skill);
} catch (e) {
  if (e.message.includes('already being installed or removed')) {
    await waitForCurrentOperation();
    await installSkill(skill); // retry once
  }
}

Prevention

When it happens

Trigger: Calling installRemotionSkillHandler or removeRemotionSkillHandler for a remotionRoot while a previous install/remove for the same root is still running (the set contains the root).

Common situations: Double-clicking the install button in Studio; two browser tabs triggering installs for the same project; an automation script firing requests without awaiting the previous one.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at packages/studio-server/src/preview-server/routes/install-remotion-skill.ts:31

const changingSkillsInProjects = new Set<string>();

const changeRemotionSkill = async ({
	action,
	remotionRoot,
	input: {skill},
	logLevel,
}: Parameters<
	ApiHandler<InstallRemotionSkillRequest, GetRemotionSkillsInfoResponse>
>[0] & {
	readonly action: 'install' | 'remove';
}): Promise<GetRemotionSkillsInfoResponse> => {
	if (!remotionSkillNames.some((name) => name === skill)) {
		throw new Error(`Unknown Remotion skill: ${JSON.stringify(skill)}`);
	}

	if (changingSkillsInProjects.has(remotionRoot)) {
		throw new Error(
			'A skill is already being installed or removed. Please try again once it finishes.',
		);
	}

	changingSkillsInProjects.add(remotionRoot);
	try {
		const installedSkill = getRemotionSkillsInfo({remotionRoot}).skills.find(
			({name}) => name === skill,
		);
		const removingGlobally =
			action === 'remove' &&
			installedSkill?.installedInProject === false &&
			installedSkill.installedGlobally;
		if (
			action === 'remove' &&
			!removingGlobally &&
			!installedSkill?.installedInProject
		) {

View on GitHub (pinned to 46a3a6bf13)