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
- Wait for the in-progress install/remove to finish (watch the Studio UI progress indicator), then retry
- Debounce or serialize requests in client code so only one skill change runs at a time per project
- 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
- Serialize skill operations: await each before starting the next
- Disable install/remove buttons while an operation is in flight
- Use a single Studio tab per project for skill management
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
- A Remotion upgrade is already in progress.
- Asset was not found in public/.
- assetPath must be a non-empty public-folder path, or an…
- AWS Concurrency limit reached
- Cannot create an undo entry without snapshots
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)